diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b5dce652c33e..665791851b83 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,6 +2,8 @@ name: GraalVM Gate on: push: + branches-ignore: + - 'github/**' paths-ignore: - '.travis.yml' - '.github/workflows/quarkus.yml' @@ -31,6 +33,7 @@ env: MX_GIT_CACHE: refcache MX_PYTHON_VERSION: 3 JAVA_HOME: ${{ github.workspace }}/jdk + JDT: builtin MX_PATH: ${{ github.workspace }}/mx jobs: @@ -122,7 +125,7 @@ jobs: env: ${{ matrix.env }} run: | mkdir jdk-dl - ${MX_PATH}/mx fetch-jdk --jdk-id ${JDK} --to jdk-dl --alias ${JAVA_HOME} + ${MX_PATH}/mx --java-home= fetch-jdk --jdk-id ${JDK} --to jdk-dl --alias ${JAVA_HOME} - name: Update dependency cache if: ${{ contains(matrix.env.GATE, 'debug') || contains(matrix.env.GATE, 'style') }} run: sudo apt update @@ -150,16 +153,6 @@ jobs: git fetch --unshallow fi - if [[ ${GATE} == *fullbuild* ]] - then - # Only test JDT on JDK8 - if [ "${JDK}" == "openjdk8" ] - then - export JDT=${MX_PATH}/ecj.jar - wget --no-verbose https://archive.eclipse.org/eclipse/downloads/drops4/R-4.14-201912100610/ecj-4.14.jar -O ${JDT} - fi - fi - echo ${JAVA_HOME} ${JAVA_HOME}/bin/java -version if [[ ${WITHOUT_VCS} ]] diff --git a/.github/workflows/quarkus.yml b/.github/workflows/quarkus.yml index f4ceb8ea570d..c00f7de796e7 100644 --- a/.github/workflows/quarkus.yml +++ b/.github/workflows/quarkus.yml @@ -63,12 +63,12 @@ jobs: - name: Get JDK run: | mkdir jdk-dl - ${MX_PATH}/mx fetch-jdk --jdk-id labsjdk-ce-11 --to jdk-dl --alias ${JAVA_HOME} + ${MX_PATH}/mx --java-home= fetch-jdk --jdk-id labsjdk-ce-11 --to jdk-dl --alias ${JAVA_HOME} - name: Build graalvm native-image run: | cd substratevm - ${MX_PATH}/mx --native=native-image --components="Native Image" build - mv $(${MX_PATH}/mx --native=native-image --components="Native Image" graalvm-home) ${GRAALVM_HOME} + ${MX_PATH}/mx --native=native-image,lib:jvmcicompiler --components="Native Image,LibGraal" build + mv $(${MX_PATH}/mx --native=native-image,lib:jvmcicompiler --components="Native Image,LibGraal" graalvm-home) ${GRAALVM_HOME} ${GRAALVM_HOME}/bin/native-image --version - name: Tar GraalVM shell: bash diff --git a/bench-common.libsonnet b/bench-common.libsonnet index d81ac3d40c7f..f78a16a7e3be 100644 --- a/bench-common.libsonnet +++ b/bench-common.libsonnet @@ -49,6 +49,13 @@ default_numa_node:: 0, num_threads:: 72 }, + x82:: common.linux + common.amd64 + self._bench_machine + { + machine_name:: "x82", + capabilities+: ["no_frequency_scaling", "tmpfs25g"], + numa_nodes:: [0, 1], + default_numa_node:: 0, + num_threads:: 96 + }, xgene3:: common.linux + common.aarch64 + self._bench_machine + { machine_name:: "xgene3", capabilities+: [], diff --git a/ci.hocon b/ci.hocon index 667507ef4749..2a99603db840 100644 --- a/ci.hocon +++ b/ci.hocon @@ -5,9 +5,6 @@ builds = [] binaries-repository = "lafo" -#SDK -include "sdk/ci.hocon" - #Truffle include "truffle/ci.hocon" @@ -18,12 +15,6 @@ logPatterns = [ ${compiler-suite-root}"/graal_dumps/*/*" ] -#Tools -include "tools/ci.hocon" - -#Regex -include "regex/ci.hocon" - #Examples #Examples gate also disabled. #include "examples/ci.hocon" @@ -54,9 +45,6 @@ include "compiler/ci_includes/bench-aarch64-c2.hocon" # ------------------ SVM ---------------------- include "substratevm/ci_includes/gate.hocon" -# Publish Javadoc -include "ci_includes/publish-javadoc.hocon" - # ------------------- VM ---------------------- include "vm/ci_common/common.hocon" include "vm/ci_common/common-bench.hocon" diff --git a/ci.jsonnet b/ci.jsonnet index 3e95ac872dc0..a50a9c1b55b8 100644 --- a/ci.jsonnet +++ b/ci.jsonnet @@ -7,14 +7,26 @@ local wasm = import 'wasm/ci.jsonnet'; # Espresso local espresso = import 'espresso/ci.jsonnet'; +# Regex +local regex = import 'regex/ci.jsonnet'; + +# SDK +local sdk = import 'sdk/ci.jsonnet'; + # Sulong local sulong = import 'sulong/ci.jsonnet'; +# Tools +local tools = import 'tools/ci.jsonnet'; + +# JavaDoc +local javadoc = import "ci_includes/publish-javadoc.jsonnet"; + # Add a guard to `build` that prevents it from running in the gate -# for a PR that only touches *.md flles. -local add_markdown_guard(build) = build + { +# for a PR that only touches *.md files, the docs, are config files for GitHub. +local add_excludes_guard(build) = build + { guard+: { - excludes+: ["**.md", "docs/**"] + excludes+: ["**.md", "docs/**", ".github/**"] } }; @@ -23,5 +35,14 @@ local add_markdown_guard(build) = build + { _checkCommon: (import 'common.jsonnet'), ci_resources:: (import 'ci-resources.libsonnet'), specVersion: "2", - builds: [add_markdown_guard(b) for b in (compiler.builds + wasm.builds + espresso.builds + sulong.builds)] + builds: [add_excludes_guard(b) for b in ( + compiler.builds + + wasm.builds + + espresso.builds + + regex.builds + + sdk.builds + + sulong.builds + + tools.builds + + javadoc.builds + )] } diff --git a/ci_includes/publish-javadoc.hocon b/ci_includes/publish-javadoc.hocon deleted file mode 100644 index 8b9ae71c1e87..000000000000 --- a/ci_includes/publish-javadoc.hocon +++ /dev/null @@ -1,44 +0,0 @@ -# Publish Javadoc of graal components post-merge - -builds += [ - ${linux-amd64} ${oraclejdk8} { - timelimit : "30:00", - run : [ - [cd, "./sdk"], - ["mx", "build"], - ["mx", "javadoc"], - ["zip", "-r", "javadoc.zip", "javadoc"], - [cd, "../truffle"], - ["mx", "build"], - ["mx", "javadoc"], - ["zip", "-r", "javadoc.zip", "javadoc"], - [cd, "../tools"], - ["mx", "build"], - ["mx", "javadoc"], - ["zip", "-r", "javadoc.zip", "javadoc"], - [cd, "../compiler"], - ["mx", "build"], - ["mx", "javadoc", "--projects", "org.graalvm.graphio"], - ["cd", "src/org.graalvm.graphio/"], - ["zip", "-r", "../../graphio-javadoc.zip", "javadoc"], - [cd, "../../.."], - [set-export, GRAAL_REPO, [pwd]], - [cd, ".."] - ["git", "clone", [mx, urlrewrite, "https://github.com/graalvm/graalvm-website.git"]], - [cd, "graalvm-website"] - ["rm", "-rf", "sdk/javadoc", "truffle/javadoc", "tools/javadoc", "graphio/javadoc"], - ["git", "status" ], - ["unzip", "-o", "-d", "sdk", "$GRAAL_REPO/sdk/javadoc.zip"], - ["unzip", "-o", "-d", "truffle", "$GRAAL_REPO/truffle/javadoc.zip"], - ["unzip", "-o", "-d", "tools", "$GRAAL_REPO/tools/javadoc.zip"], - ["unzip", "-o", "-d", "graphio", "$GRAAL_REPO/compiler/graphio-javadoc.zip"], - ["git", "add", "sdk/javadoc", "truffle/javadoc", "tools/javadoc", "graphio/javadoc"], - ["git", "config", "user.name", "Javadoc Publisher"], - ["git", "config", "user.email", "graal-dev@openjdk.java.net"], - ["git", "diff", "--staged", "--quiet", "||", "git", "commit", "-m", [ "echo", "Javadoc as of", [ "date", "+%Y/%m/%d" ] ] ], - ["git", "push", "origin", "HEAD"], - ], - targets : [post-merge], - name: "graal-publish-javadoc" - } -] diff --git a/ci_includes/publish-javadoc.jsonnet b/ci_includes/publish-javadoc.jsonnet new file mode 100644 index 000000000000..cdb68e132b8e --- /dev/null +++ b/ci_includes/publish-javadoc.jsonnet @@ -0,0 +1,52 @@ +{ + local common = import '../common.jsonnet', + local utils = import '../common-utils.libsonnet', + local linux_amd64 = common["linux-amd64"], + + local javadoc_publisher = { + name: 'graal-publish-javadoc-' + utils.prefixed_jdk(self.jdk_version), + run+: [ + ["cd", "./sdk"], + ["mx", "build"], + ["mx", "javadoc"], + ["zip", "-r", "javadoc.zip", "javadoc"], + ["cd", "../truffle"], + ["mx", "build"], + ["mx", "javadoc"], + ["zip", "-r", "javadoc.zip", "javadoc"], + ["cd", "../tools"], + ["mx", "build"], + ["mx", "javadoc"], + ["zip", "-r", "javadoc.zip", "javadoc"], + ["cd", "../compiler"], + ["mx", "build"], + ["mx", "javadoc", "--projects", "org.graalvm.graphio"], + ["cd", "src/org.graalvm.graphio/"], + ["zip", "-r", "../../graphio-javadoc.zip", "javadoc"], + ["cd", "../../.."], + ["set-export", "GRAAL_REPO", ["pwd"]], + ["cd", ".."], + ["git", "clone", ["mx", "urlrewrite", "https://github.com/graalvm/graalvm-website.git"]], + ["cd", "graalvm-website"], + ["rm", "-rf", "sdk/javadoc", "truffle/javadoc", "tools/javadoc", "graphio/javadoc"], + ["git", "status" ], + ["unzip", "-o", "-d", "sdk", "$GRAAL_REPO/sdk/javadoc.zip"], + ["unzip", "-o", "-d", "truffle", "$GRAAL_REPO/truffle/javadoc.zip"], + ["unzip", "-o", "-d", "tools", "$GRAAL_REPO/tools/javadoc.zip"], + ["unzip", "-o", "-d", "graphio", "$GRAAL_REPO/compiler/graphio-javadoc.zip"], + ["git", "add", "sdk/javadoc", "truffle/javadoc", "tools/javadoc", "graphio/javadoc"], + ["git", "config", "user.name", "Javadoc Publisher"], + ["git", "config", "user.email", "graal-dev@openjdk.java.net"], + ["git", "diff", "--staged", "--quiet", "||", "git", "commit", "-m", ["echo", "Javadoc as of", ["date", "+%Y/%m/%d"]]], + ["git", "push", "origin", "HEAD"] + ], + notify_groups:: ["javadoc"], + timelimit : "30:00" + }, + + local all_builds = [ + common.post_merge + linux_amd64 + common.oraclejdk8 + javadoc_publisher, + ], + // adds a "defined_in" field to all builds mentioning the location of this current file + builds:: [{ defined_in: std.thisFile } + b for b in all_builds] +} diff --git a/common.hocon b/common.hocon index 499cdfa0cd62..af5f11e7a34a 100644 --- a/common.hocon +++ b/common.hocon @@ -43,9 +43,7 @@ labsjdk-ce-17Debug : { downloads : { JAVA_HOME : ${jdks.labsjdk-ce-17Debug} }} labsjdk-ee-17Debug : { downloads : { JAVA_HOME : ${jdks.labsjdk-ee-17Debug} }} common : ${mx} ${deps.common} { - catch_files : [ - "Graal diagnostic output saved in (?P.+\.zip)" - ] + catch_files : ${catch_files} } linux : ${common} ${deps.linux} diff --git a/common.json b/common.json index 074ef663904f..0b924c3f20ac 100644 --- a/common.json +++ b/common.json @@ -2,29 +2,35 @@ "README": "This file contains definitions that are useful for the hocon and jsonnet CI files of multiple repositories.", "jdks": { - "openjdk8": {"name": "openjdk", "version": "8u302+06-jvmci-21.3-b02", "platformspecific": true }, - "oraclejdk8": {"name": "oraclejdk", "version": "8u311+06-jvmci-21.3-b02", "platformspecific": true }, - "oraclejdk8Debug": {"name": "oraclejdk", "version": "8u311+06-jvmci-21.3-b02-fastdebug", "platformspecific": true }, + "openjdk8": {"name": "openjdk", "version": "8u302+06-jvmci-21.3-b03", "platformspecific": true }, + "oraclejdk8": {"name": "oraclejdk", "version": "8u311+09-jvmci-21.3-b03", "platformspecific": true }, + "oraclejdk8Debug": {"name": "oraclejdk", "version": "8u311+09-jvmci-21.3-b03-fastdebug", "platformspecific": true }, "openjdk11": {"name": "openjdk", "version": "11.0.11+9", "platformspecific": true }, "oraclejdk11": {"name": "oraclejdk", "version": "11.0.11+9", "platformspecific": true }, - "labsjdk-ce-11": {"name": "labsjdk", "version": "ce-11.0.12+5-jvmci-21.3-b02", "platformspecific": true }, - "labsjdk-ee-11": {"name": "labsjdk", "version": "ee-11.0.13+6-jvmci-21.3-b02", "platformspecific": true }, + "labsjdk-ce-11": {"name": "labsjdk", "version": "ce-11.0.12+5-jvmci-21.3-b03", "platformspecific": true }, + "labsjdk-ee-11": {"name": "labsjdk", "version": "ee-11.0.13+9-jvmci-21.3-b03", "platformspecific": true }, - "oraclejdk17": {"name": "oraclejdk", "version": "17.0.1+2", "platformspecific": true }, - "labsjdk-ce-17": {"name": "labsjdk", "version": "ce-17+35-jvmci-21.3-b02", "platformspecific": true }, - "labsjdk-ce-17Debug": {"name": "labsjdk", "version": "ce-17+35-jvmci-21.3-b02-debug", "platformspecific": true }, - "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.1+7-jvmci-21.3-b02", "platformspecific": true }, - "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.1+7-jvmci-21.3-b02-debug", "platformspecific": true } + "oraclejdk17": {"name": "oraclejdk", "version": "17.0.1+12", "platformspecific": true }, + "labsjdk-ce-17": {"name": "labsjdk", "version": "ce-17+35-jvmci-21.3-b03", "platformspecific": true }, + "labsjdk-ce-17Debug": {"name": "labsjdk", "version": "ce-17+35-jvmci-21.3-b03-debug", "platformspecific": true }, + "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.1+9-jvmci-21.3-b03", "platformspecific": true }, + "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.1+9-jvmci-21.3-b03-debug", "platformspecific": true } }, - "COMMENT" : "The devkits versions reflect those used to build the JVMCI JDKs (e.g., see devkit_platform_revisions in /make/conf/jib-profiles.js)", + "COMMENT.devkits" : "The devkits versions reflect those used to build the JVMCI JDKs (e.g., see devkit_platform_revisions in /make/conf/jib-profiles.js)", "devkits": { "windows-oraclejdk8": { "packages" : { "devkit:VS2017-15.9.16+1" : "==0" }}, "windows-openjdk8": { "packages" : { "devkit:VS2017-15.9.16+1" : "==0" }}, "windows-jdk11": { "packages" : { "devkit:VS2017-15.9.24+1" : "==0" }}, "windows-jdk17": { "packages" : { "devkit:VS2019-16.9.3+1" : "==0" }} }, + + "catch_files" : [ + "Graal diagnostic output saved in '(?P[^']+)'", + "Dumping debug output to '(?P[^']+)'" + ], + "deps": { "COMMENT.common": [ "pip:isort is a dependency of pip:pylint. The explicit dependency on the pip package works around", @@ -78,12 +84,8 @@ } }, "jdt": { - "downloads": { - "JDT": { - "name": "ecj", - "version": "4.14.0", - "platformspecific": false - } + "environment": { + "JDT": "builtin" } } }, diff --git a/common.jsonnet b/common.jsonnet index 4944c97b44d9..30367145916c 100644 --- a/common.jsonnet +++ b/common.jsonnet @@ -105,9 +105,7 @@ # enforce self.arch (useful for generating job names) arch:: error "self.arch not set", capabilities +: [], - catch_files +: [ - "Graal diagnostic output saved in (?P.+\\.zip)" - ] + catch_files +: common_json.catch_files }, linux:: deps.linux + self.common + { diff --git a/compiler/CHANGELOG.md b/compiler/CHANGELOG.md index f6f999f8baef..9dbdd4837d9d 100644 --- a/compiler/CHANGELOG.md +++ b/compiler/CHANGELOG.md @@ -2,6 +2,9 @@ This changelog summarizes newly introduced optimizations that may be relevant to other teams. +## Version 22.0.0 +* (GR-22707) (GR-30838): New, inner loops first, reverse post order and loop frequency calculations for the compiler. + ## Version 21.2.0 * (GR-29770) Loop safepoint elimination: Not only consider 32bit loops for safepoint removal but also 64bit ones that iterate in 32bit ranges. diff --git a/compiler/ci_common/benchmark-builders.jsonnet b/compiler/ci_common/benchmark-builders.jsonnet index a7d2919aede3..fca206f76905 100644 --- a/compiler/ci_common/benchmark-builders.jsonnet +++ b/compiler/ci_common/benchmark-builders.jsonnet @@ -5,123 +5,52 @@ local bench = (import 'benchmark-suites.libsonnet'), local hw = bc.bench_hw, - local jdk8 = c.oraclejdk8, - local jdk11 = c.labsjdk11, - local jdk17 = c.labsjdk17, - - local amd64_jdks = [jdk8, jdk11, jdk17], - local aarch64_jdks = [jdk11, jdk17], - - local main_builds = [ - c.daily + hw.x52 + jdk8 + cc.libgraal + bench.dacapo, - c.daily + hw.x52 + jdk8 + cc.jargraal + bench.dacapo, - c.weekly + hw.x52 + jdk8 + cc.libgraal + bench.dacapo_size_variants, - c.on_demand + hw.x52 + jdk8 + cc.jargraal + bench.dacapo_size_variants, - c.weekly + hw.x52 + jdk8 + cc.libgraal + bench.dacapo_timing, - c.weekly + hw.x52 + jdk8 + cc.jargraal + bench.dacapo_timing, - c.daily + hw.x52 + jdk8 + cc.libgraal + bench.scala_dacapo, - c.daily + hw.x52 + jdk8 + cc.jargraal + bench.scala_dacapo, - c.weekly + hw.x52 + jdk8 + cc.libgraal + bench.scala_dacapo_size_variants, - c.on_demand + hw.x52 + jdk8 + cc.jargraal + bench.scala_dacapo_size_variants, - c.weekly + hw.x52 + jdk8 + cc.libgraal + bench.scala_dacapo_timing, - c.weekly + hw.x52 + jdk8 + cc.jargraal + bench.scala_dacapo_timing, - c.post_merge + hw.x52 + jdk8 + cc.libgraal + bench.renaissance, - c.daily + hw.x52 + jdk8 + cc.jargraal + bench.renaissance, - c.daily + hw.x52 + jdk8 + cc.libgraal + bench.specjvm2008, - c.weekly + hw.x52 + jdk8 + cc.jargraal + bench.specjvm2008, - c.daily + hw.x52 + jdk8 + cc.libgraal + bench.specjbb2005, - c.weekly + hw.x52 + jdk8 + cc.jargraal + bench.specjbb2005, - c.weekly + hw.x52 + jdk8 + cc.libgraal + bench.specjbb2015, - c.weekly + hw.x52 + jdk8 + cc.jargraal + bench.specjbb2015, - c.weekly + hw.x52 + jdk8 + cc.libgraal + bench.specjbb2015_full_machine, - c.on_demand + hw.x52 + jdk8 + cc.jargraal + bench.specjbb2015_full_machine, - c.weekly + hw.x52 + jdk8 + cc.libgraal + bench.renaissance_0_10, - c.on_demand + hw.x52 + jdk8 + cc.jargraal + bench.renaissance_0_10, - c.daily + hw.x52 + jdk8 + cc.libgraal + bench.awfy, - c.daily + hw.x52 + jdk8 + cc.jargraal + bench.awfy, - c.daily + hw.x52 + jdk8 + cc.libgraal + bench.renaissance_legacy, - c.daily + hw.x52 + jdk8 + cc.jargraal + bench.renaissance_legacy, - c.daily + hw.x52 + jdk8 + cc.libgraal + bench.micros_graal_whitebox, - c.weekly + hw.x52 + jdk8 + cc.jargraal + bench.micros_graal_whitebox, - c.daily + hw.x52 + jdk8 + cc.libgraal + bench.micros_graal_dist, - c.weekly + hw.x52 + jdk8 + cc.jargraal + bench.micros_graal_dist, - c.daily + hw.x52 + jdk8 + cc.libgraal + bench.micros_misc_graal_dist, - c.weekly + hw.x52 + jdk8 + cc.jargraal + bench.micros_misc_graal_dist, - c.daily + hw.x52 + jdk8 + cc.libgraal + bench.micros_shootout_graal_dist, - c.weekly + hw.x52 + jdk8 + cc.jargraal + bench.micros_shootout_graal_dist, - - c.post_merge + hw.x52 + jdk11 + cc.libgraal + bench.dacapo, - c.daily + hw.x52 + jdk11 + cc.jargraal + bench.dacapo, - c.weekly + hw.x52 + jdk11 + cc.libgraal + bench.dacapo_size_variants, - c.weekly + hw.x52 + jdk11 + cc.jargraal + bench.dacapo_size_variants, - c.weekly + hw.x52 + jdk11 + cc.libgraal + bench.dacapo_timing, - c.weekly + hw.x52 + jdk11 + cc.jargraal + bench.dacapo_timing, - c.post_merge + hw.x52 + jdk11 + cc.libgraal + bench.scala_dacapo, - c.daily + hw.x52 + jdk11 + cc.jargraal + bench.scala_dacapo, - c.weekly + hw.x52 + jdk11 + cc.libgraal + bench.scala_dacapo_size_variants, - c.weekly + hw.x52 + jdk11 + cc.jargraal + bench.scala_dacapo_size_variants, - c.weekly + hw.x52 + jdk11 + cc.libgraal + bench.scala_dacapo_timing, - c.weekly + hw.x52 + jdk11 + cc.jargraal + bench.scala_dacapo_timing, - c.post_merge + hw.x52 + jdk11 + cc.libgraal + bench.renaissance, - c.daily + hw.x52 + jdk11 + cc.jargraal + bench.renaissance, - c.post_merge + hw.x52 + jdk11 + cc.libgraal + bench.specjvm2008, - c.daily + hw.x52 + jdk11 + cc.jargraal + bench.specjvm2008, - c.daily + hw.x52 + jdk11 + cc.libgraal + bench.specjbb2005, - c.daily + hw.x52 + jdk11 + cc.jargraal + bench.specjbb2005, - c.daily + hw.x52 + jdk11 + cc.libgraal + bench.specjbb2015, - c.weekly + hw.x52 + jdk11 + cc.jargraal + bench.specjbb2015, - c.weekly + hw.x52 + jdk11 + cc.libgraal + bench.specjbb2015_full_machine, - c.on_demand + hw.x52 + jdk11 + cc.jargraal + bench.specjbb2015_full_machine, - c.weekly + hw.x52 + jdk11 + cc.libgraal + bench.renaissance_0_10, - c.on_demand + hw.x52 + jdk11 + cc.jargraal + bench.renaissance_0_10, - c.daily + hw.x52 + jdk11 + cc.libgraal + bench.awfy, - c.daily + hw.x52 + jdk11 + cc.jargraal + bench.awfy, - c.post_merge + hw.x52 + jdk11 + cc.libgraal + bench.renaissance_legacy, - c.daily + hw.x52 + jdk11 + cc.jargraal + bench.renaissance_legacy, - c.daily + hw.x52 + jdk11 + cc.libgraal + bench.micros_graal_whitebox, - c.weekly + hw.x52 + jdk11 + cc.jargraal + bench.micros_graal_whitebox, - c.daily + hw.x52 + jdk11 + cc.libgraal + bench.micros_graal_dist, - c.weekly + hw.x52 + jdk11 + cc.jargraal + bench.micros_graal_dist, - c.daily + hw.x52 + jdk11 + cc.libgraal + bench.micros_misc_graal_dist, - c.weekly + hw.x52 + jdk11 + cc.jargraal + bench.micros_misc_graal_dist, - c.daily + hw.x52 + jdk11 + cc.libgraal + bench.micros_shootout_graal_dist, - c.weekly + hw.x52 + jdk11 + cc.jargraal + bench.micros_shootout_graal_dist, + local main_builds = std.flattenArrays([ + [ + c.post_merge + hw.x52 + jdk + cc.libgraal + bench.dacapo, + c.daily + hw.x52 + jdk + cc.jargraal + bench.dacapo, + c.weekly + hw.x52 + jdk + cc.libgraal + bench.dacapo_size_variants, + c.weekly + hw.x52 + jdk + cc.jargraal + bench.dacapo_size_variants, + c.weekly + hw.x52 + jdk + cc.libgraal + bench.dacapo_timing, + c.weekly + hw.x52 + jdk + cc.jargraal + bench.dacapo_timing, + c.post_merge + hw.x52 + jdk + cc.libgraal + bench.scala_dacapo, + c.daily + hw.x52 + jdk + cc.jargraal + bench.scala_dacapo, + c.weekly + hw.x52 + jdk + cc.libgraal + bench.scala_dacapo_size_variants, + c.weekly + hw.x52 + jdk + cc.jargraal + bench.scala_dacapo_size_variants, + c.weekly + hw.x52 + jdk + cc.libgraal + bench.scala_dacapo_timing, + c.weekly + hw.x52 + jdk + cc.jargraal + bench.scala_dacapo_timing, + c.post_merge + hw.x52 + jdk + cc.libgraal + bench.renaissance, + c.daily + hw.x52 + jdk + cc.jargraal + bench.renaissance, + c.post_merge + hw.x52 + jdk + cc.libgraal + bench.specjvm2008, + c.daily + hw.x52 + jdk + cc.jargraal + bench.specjvm2008, + c.daily + hw.x52 + jdk + cc.libgraal + bench.specjbb2005, + c.daily + hw.x52 + jdk + cc.jargraal + bench.specjbb2005, + c.daily + hw.x52 + jdk + cc.libgraal + bench.specjbb2015, + c.weekly + hw.x52 + jdk + cc.jargraal + bench.specjbb2015, + c.weekly + hw.x52 + jdk + cc.libgraal + bench.specjbb2015_full_machine, + c.on_demand + hw.x52 + jdk + cc.jargraal + bench.specjbb2015_full_machine, + c.weekly + hw.x52 + jdk + cc.libgraal + bench.renaissance_0_10, + c.on_demand + hw.x52 + jdk + cc.jargraal + bench.renaissance_0_10, + c.weekly + hw.x52 + jdk + cc.libgraal + bench.renaissance_0_13, + c.on_demand + hw.x52 + jdk + cc.jargraal + bench.renaissance_0_13, + c.daily + hw.x52 + jdk + cc.libgraal + bench.awfy, + c.daily + hw.x52 + jdk + cc.jargraal + bench.awfy, + c.daily + hw.x52 + jdk + cc.libgraal + bench.microservice_benchmarks, + c.weekly + hw.x52 + jdk + cc.jargraal + bench.microservice_benchmarks, + c.post_merge + hw.x52 + jdk + cc.libgraal + bench.renaissance_legacy, + c.daily + hw.x52 + jdk + cc.jargraal + bench.renaissance_legacy, + c.daily + hw.x52 + jdk + cc.libgraal + bench.micros_graal_whitebox, + c.weekly + hw.x52 + jdk + cc.jargraal + bench.micros_graal_whitebox, + c.daily + hw.x52 + jdk + cc.libgraal + bench.micros_graal_dist, + c.weekly + hw.x52 + jdk + cc.jargraal + bench.micros_graal_dist, + c.daily + hw.x52 + jdk + cc.libgraal + bench.micros_misc_graal_dist, + c.weekly + hw.x52 + jdk + cc.jargraal + bench.micros_misc_graal_dist, + c.daily + hw.x52 + jdk + cc.libgraal + bench.micros_shootout_graal_dist, + c.weekly + hw.x52 + jdk + cc.jargraal + bench.micros_shootout_graal_dist, + ] + for jdk in cc.bench_jdks + ]), - c.daily + hw.x52 + jdk17 + cc.libgraal + bench.dacapo, - c.daily + hw.x52 + jdk17 + cc.jargraal + bench.dacapo, - c.daily + hw.x52 + jdk17 + cc.libgraal + bench.dacapo_size_variants, - c.weekly + hw.x52 + jdk17 + cc.jargraal + bench.dacapo_size_variants, - c.weekly + hw.x52 + jdk17 + cc.libgraal + bench.dacapo_timing, - c.weekly + hw.x52 + jdk17 + cc.jargraal + bench.dacapo_timing, - c.daily + hw.x52 + jdk17 + cc.libgraal + bench.scala_dacapo, - c.daily + hw.x52 + jdk17 + cc.jargraal + bench.scala_dacapo, - c.daily + hw.x52 + jdk17 + cc.libgraal + bench.scala_dacapo_size_variants, - c.weekly + hw.x52 + jdk17 + cc.jargraal + bench.scala_dacapo_size_variants, - c.weekly + hw.x52 + jdk17 + cc.libgraal + bench.scala_dacapo_timing, - c.weekly + hw.x52 + jdk17 + cc.jargraal + bench.scala_dacapo_timing, - #c.post_merge + hw.x52 + jdk17 + cc.libgraal + bench.renaissance, - #c.daily + hw.x52 + jdk17 + cc.jargraal + bench.renaissance, - c.daily + hw.x52 + jdk17 + cc.libgraal + bench.specjvm2008, - c.daily + hw.x52 + jdk17 + cc.jargraal + bench.specjvm2008, - c.daily + hw.x52 + jdk17 + cc.libgraal + bench.specjbb2005, - c.daily + hw.x52 + jdk17 + cc.jargraal + bench.specjbb2005, - c.daily + hw.x52 + jdk17 + cc.libgraal + bench.specjbb2015, - c.weekly + hw.x52 + jdk17 + cc.jargraal + bench.specjbb2015, - c.weekly + hw.x52 + jdk17 + cc.libgraal + bench.specjbb2015_full_machine, - c.on_demand + hw.x52 + jdk17 + cc.jargraal + bench.specjbb2015_full_machine, - c.daily + hw.x52 + jdk17 + cc.libgraal + bench.awfy, - c.daily + hw.x52 + jdk17 + cc.jargraal + bench.awfy, - #c.post_merge + hw.x52 + jdk17 + cc.libgraal + bench.renaissance_legacy, - #c.daily + hw.x52 + jdk17 + cc.jargraal + bench.renaissance_legacy, - c.daily + hw.x52 + jdk17 + cc.libgraal + bench.micros_graal_whitebox, - c.weekly + hw.x52 + jdk17 + cc.jargraal + bench.micros_graal_whitebox, - c.daily + hw.x52 + jdk17 + cc.libgraal + bench.micros_graal_dist, - c.weekly + hw.x52 + jdk17 + cc.jargraal + bench.micros_graal_dist, - c.daily + hw.x52 + jdk17 + cc.libgraal + bench.micros_misc_graal_dist, - c.weekly + hw.x52 + jdk17 + cc.jargraal + bench.micros_misc_graal_dist, - c.daily + hw.x52 + jdk17 + cc.libgraal + bench.micros_shootout_graal_dist, - c.weekly + hw.x52 + jdk17 + cc.jargraal + bench.micros_shootout_graal_dist - ], // JFR and async-profiler jobs local profiling_builds = std.flattenArrays([ @@ -129,28 +58,15 @@ c.weekly + hw.x52 + jdk + cc.libgraal + cc.enable_profiling + suite + { job_prefix:: "bench-profiling" }, c.weekly + hw.x52 + jdk + cc.jargraal + cc.enable_profiling + suite + { job_prefix:: "bench-profiling" } ] - for jdk in amd64_jdks + for jdk in cc.bench_jdks for suite in bench.groups.profiled_suites - if suite.is_jdk_supported(jdk.jdk_version) - ]), - - // Microservices - local microservice_builds = std.flattenArrays([ - [ - c.daily + hw.x52 + jdk + cc.libgraal + suite, - c.weekly + hw.x52 + jdk + cc.jargraal + suite - ] - for jdk in amd64_jdks - for suite in bench.groups.microservice_suites - if suite.is_jdk_supported(jdk.jdk_version) ]), // intensive weekly benchmarking local weekly_forks_builds = std.flattenArrays([ bc.generate_fork_builds(c.weekly + hw.x52 + jdk + cc.libgraal + suite, subdir='compiler') - for jdk in amd64_jdks + for jdk in cc.bench_jdks for suite in bench.groups.weekly_forks_suites - if suite.is_jdk_supported(jdk.jdk_version) ]), local aarch64_builds = std.flattenArrays([ @@ -158,12 +74,12 @@ c.weekly + hw.xgene3 + jdk + cc.libgraal + suite, c.weekly + hw.xgene3 + jdk + cc.jargraal + suite ] - for jdk in aarch64_jdks + for jdk in cc.bench_jdks for suite in bench.groups.main_suites - if suite.is_jdk_supported(jdk.jdk_version) ]), - local all_builds = main_builds + weekly_forks_builds + profiling_builds + microservice_builds + aarch64_builds, + local all_builds = main_builds + weekly_forks_builds + profiling_builds + aarch64_builds, + local filtered_builds = [b for b in all_builds if b.is_jdk_supported(b.jdk_version)], // adds a "defined_in" field to all builds mentioning the location of this current file - builds:: [{ defined_in: std.thisFile } + b for b in all_builds] + builds:: [{ defined_in: std.thisFile } + b for b in filtered_builds] } diff --git a/compiler/ci_common/benchmark-suites.libsonnet b/compiler/ci_common/benchmark-suites.libsonnet index aeb2e0c41fe0..ad9d8580b6e7 100644 --- a/compiler/ci_common/benchmark-suites.libsonnet +++ b/compiler/ci_common/benchmark-suites.libsonnet @@ -11,13 +11,13 @@ legacy_and_secondary_suites:: std.set([$.renaissance_legacy, $.dacapo_size_variants, $.scala_dacapo_size_variants], keyF=uniq_key), jmh_micros_suites:: std.set([$.micros_graal_dist, $.micros_misc_graal_dist , $.micros_shootout_graal_dist], keyF=uniq_key), graal_internals_suites:: std.set([$.micros_graal_whitebox], keyF=uniq_key), - special_suites:: std.set([$.renaissance_0_10, $.specjbb2015_full_machine], keyF=uniq_key), + special_suites:: std.set([$.renaissance_0_10, $.renaissance_0_13, $.specjbb2015_full_machine], keyF=uniq_key), microservice_suites:: std.set([$.microservice_benchmarks], keyF=uniq_key), main_suites:: std.set(self.open_suites + self.spec_suites + self.legacy_and_secondary_suites, keyF=uniq_key), all_suites:: std.set(self.main_suites + self.jmh_micros_suites + self.special_suites + self.microservice_suites, keyF=uniq_key), - weekly_forks_suites:: self.main_suites, + weekly_forks_suites:: std.set([$.renaissance_0_13] + self.main_suites, keyF=uniq_key), profiled_suites:: std.setDiff(self.main_suites, [$.specjbb2015], keyF=uniq_key), }, @@ -42,7 +42,7 @@ ], timelimit: "45:00", forks_batches:: 1, - forks_timelimit:: "02:45:00", + forks_timelimit:: "04:00:00", min_jdk_version:: 8, max_jdk_version:: null }, @@ -121,10 +121,7 @@ "SPARK_LOCAL_IP": "127.0.0.1" }, run+: [ - if self.arch == "aarch64" then - self.benchmark_cmd + ["renaissance:~db-shootout", "--bench-suite-version=$RENAISSANCE_VERSION", "--"] + self.extra_vm_args - else - self.benchmark_cmd + ["renaissance:*", "--bench-suite-version=$RENAISSANCE_VERSION", "--"] + self.extra_vm_args + self.benchmark_cmd + ["renaissance:*", "--bench-suite-version=$RENAISSANCE_VERSION", "--"] + self.extra_vm_args ], timelimit: "3:00:00", forks_batches:: 4, @@ -142,6 +139,15 @@ max_jdk_version:: 11 }, + renaissance_0_13: self.renaissance + { + suite:: "renaissance-0-13", + environment+: { + "RENAISSANCE_VERSION": "0.13.0" + }, + min_jdk_version:: 8, + max_jdk_version:: null + }, + renaissance_legacy: cc.compiler_benchmark + c.heap.default + { suite:: "renaissance-legacy", downloads+: { diff --git a/compiler/ci_common/compiler-common.libsonnet b/compiler/ci_common/compiler-common.libsonnet index 03664e6216fe..7c3cfdb0954c 100644 --- a/compiler/ci_common/compiler-common.libsonnet +++ b/compiler/ci_common/compiler-common.libsonnet @@ -16,6 +16,8 @@ ] }, + bench_jdks:: [common.labsjdk11, common.labsjdk17], + // Benchmarking building blocks // **************************** compiler_bench_base:: bench_common.bench_base + { diff --git a/compiler/ci_common/gate_tasks.hocon b/compiler/ci_common/gate_tasks.hocon index 24c3d028996c..82d03f98bb6f 100644 --- a/compiler/ci_common/gate_tasks.hocon +++ b/compiler/ci_common/gate_tasks.hocon @@ -34,7 +34,7 @@ builds += [ ${gateStyle} ${oraclejdk8} ${gateLinuxAMD64} {name: "gate-compiler-style-linux-amd64", timelimit: "45:00"} ${gateCoverage} ${oraclejdk8} ${gateLinuxAMD64} {name: "weekly-compiler-coverage-8-linux-amd64"} ${graalWeekly} {timelimit: "1:50:00"} - ${gateTest} ${labsjdk-ee-11} ${gateLinuxAMD64AVX3} {name: "gate-compiler-test-labsjdk-ee-11-linux-amd64-avx3", targets: [gate]} + ${gateTest} ${labsjdk-ee-11} ${gateLinuxAMD64AVX3} {name: "gate-compiler-test-labsjdk-ee-11-linux-amd64-avx3", targets: [gate], timelimit: "45:00"} ${gateTestCompileImmediately} ${oraclejdk8} ${gateLinuxAMD64} {name: "gate-compiler-test-truffle-compile-immediately-8-linux-amd64", timelimit: "1:00:00"} # Linux AArch64 diff --git a/compiler/ci_includes/baseline-benchmarks.jsonnet b/compiler/ci_includes/baseline-benchmarks.jsonnet index 4f31beedcbf5..eb1f49d3343b 100644 --- a/compiler/ci_includes/baseline-benchmarks.jsonnet +++ b/compiler/ci_includes/baseline-benchmarks.jsonnet @@ -5,18 +5,10 @@ local bench = (import '../ci_common/benchmark-suites.libsonnet'), local hw = bc.bench_hw, - local jdk8 = c.oraclejdk8, - local jdk11 = c.labsjdk11, - local jdk17 = c.labsjdk17, - - local amd64_jdks = [jdk8, jdk11, jdk17], - local aarch64_jdks = [jdk11, jdk17], - local hotspot_main_builds = [ c.weekly + hw.x52 + jdk + cc.c2 + suite - for jdk in amd64_jdks + for jdk in cc.bench_jdks for suite in bench.groups.all_suites - if suite.is_jdk_supported(jdk.jdk_version) ], @@ -24,28 +16,26 @@ [ c.weekly + hw.x52 + jdk + cc.c2 + cc.enable_profiling + suite + { job_prefix:: "bench-profiling" } ] - for jdk in amd64_jdks + for jdk in cc.bench_jdks for suite in bench.groups.profiled_suites - if suite.is_jdk_supported(jdk.jdk_version) ]), local weekly_forks_builds = std.flattenArrays([ bc.generate_fork_builds(c.weekly + hw.x52 + jdk + cc.c2 + suite) - for jdk in amd64_jdks + for jdk in cc.bench_jdks for suite in bench.groups.weekly_forks_suites - if suite.is_jdk_supported(jdk.jdk_version) ]), local aarch64_builds = std.flattenArrays([ [ c.weekly + hw.xgene3 + jdk + cc.c2 + suite ] - for jdk in aarch64_jdks + for jdk in cc.bench_jdks for suite in bench.groups.main_suites - if suite.is_jdk_supported(jdk.jdk_version) ]), local all_builds = hotspot_main_builds + hotspot_profiling_builds + weekly_forks_builds + aarch64_builds, + local filtered_builds = [b for b in all_builds if b.is_jdk_supported(b.jdk_version)], // adds a "defined_in" field to all builds mentioning the location of this current file - builds:: [{ defined_in: std.thisFile } + b for b in all_builds] + builds:: [{ defined_in: std.thisFile } + b for b in filtered_builds] } \ No newline at end of file diff --git a/compiler/ci_includes/gate.jsonnet b/compiler/ci_includes/gate.jsonnet index e9ada1369f48..2cf427ef325e 100644 --- a/compiler/ci_includes/gate.jsonnet +++ b/compiler/ci_includes/gate.jsonnet @@ -1,10 +1,11 @@ { - local common = (import '../../common.jsonnet'), + local common = import '../../common.jsonnet', + local utils = import '../../common-utils.libsonnet', local config = import '../../repo-configuration.libsonnet', local linux_amd64 = common["linux-amd64"], - local gateMathStubsListener = common.daily + linux_amd64 + common.oraclejdk8 + { - name: 'daily-hotspot-mathstubs-listener', + local gate_math_stubs_listener = { + name: 'daily-hotspot-mathstubs-listener-' + utils.prefixed_jdk(self.jdk_version), environment+: { "HOTSPOT_PORT_SYNC_CHECK" : "true" }, @@ -14,12 +15,11 @@ run+: [ ["mx", "build"] ], - notify_emails: [ - "yudi.zheng@oracle.com" - ], + timelimit : "10:00", + notify_groups:: ["compiler_stubs"], }, builds: [ - gateMathStubsListener, + common.daily + linux_amd64 + common.oraclejdk8 + gate_math_stubs_listener, ] } diff --git a/compiler/mx.compiler/mx_compiler.py b/compiler/mx.compiler/mx_compiler.py index 48d016eb2f30..514d85c63fec 100644 --- a/compiler/mx.compiler/mx_compiler.py +++ b/compiler/mx.compiler/mx_compiler.py @@ -28,7 +28,7 @@ from __future__ import print_function import os -from os.path import join, exists, getmtime, basename, dirname, isdir, islink +from os.path import join, exists, getmtime, basename, dirname, isdir from argparse import ArgumentParser, RawDescriptionHelpFormatter, REMAINDER import re import stat @@ -36,17 +36,14 @@ import tarfile import subprocess import tempfile -import shutil import sys -import hashlib -import io import mx_truffle import mx_sdk_vm import mx import mx_gate -from mx_gate import Task +from mx_gate import Task, Tags from mx import SafeDirectoryUpdater import mx_unittest @@ -55,7 +52,6 @@ from mx_javamodules import as_java_module from mx_updategraalinopenjdk import updategraalinopenjdk from mx_renamegraalpackages import renamegraalpackages -from mx_sdk_vm import jlink_new_jdk import mx_sdk_vm_impl import mx_benchmark @@ -162,6 +158,23 @@ def source_supplier(): mx_gate.add_jacoco_excludes(['com.oracle.truffle']) mx_gate.add_jacoco_excluded_annotations(['@Snippet', '@ClassSubstitution']) +def _get_graal_option(vmargs, name, default=None, prefix='-Dgraal.'): + """ + Gets the value of the `name` Graal option in `vmargs`. + + :param list vmargs: VM arguments to inspect + :param str name: the name of the option + :param default: the default value of the option if it's not present in `vmargs` + :param str prefix: the prefix used for Graal options in `vmargs` + :return: the value of the option as specified in `vmargs` or `default` + """ + if vmargs: + for arg in reversed(vmargs): + selector = prefix + name + '=' + if arg.startswith(selector): + return arg[len(selector):] + return default + def _get_XX_option_value(vmargs, name, default): """ Gets the value of an ``-XX:`` style HotSpot VM option. @@ -362,18 +375,36 @@ def _remove_empty_entries(a): return [] return [x for x in a if x] -def _is_batik_supported(jdk): +def _compiler_error_options(default_compilation_failure_action='ExitVM', vmargs=None, prefix='-Dgraal.'): """ - Determines if Batik runs on the given jdk. Batik's JPEGRegistryEntry contains a reference - to TruncatedFileException, which is specific to the Sun/Oracle JDK. On a different JDK, - this results in a NoClassDefFoundError: com/sun/image/codec/jpeg/TruncatedFileException + Gets options to be prefixed to the VM command line related to Graal compilation errors to improve + the chance of graph dumps being emitted and preserved in CI build logs. + + :param str default_compilation_failure_action: value for CompilationFailureAction if it is added + :param list vmargs: arguments to search for existing instances of the options added by this method + :param str prefix: the prefix used for Graal options in `vmargs` and to use when adding options """ - try: - subprocess.check_output([jdk.javap, 'com.sun.image.codec.jpeg.TruncatedFileException']) - return True - except subprocess.CalledProcessError: - mx.warn('Batik uses Sun internal class com.sun.image.codec.jpeg.TruncatedFileException which is not present in ' + jdk.home) - return False + action = _get_graal_option(vmargs, 'CompilationFailureAction') + res = [] + + # Add CompilationFailureAction if absent from vmargs + if action is None: + action = default_compilation_failure_action + res.append(prefix + 'CompilationFailureAction=' + action) + + # Add DumpOnError=true if absent from vmargs and CompilationFailureAction is Diagnose or ExitVM. + dump_on_error = _get_graal_option(vmargs, 'DumpOnError', prefix=prefix) + if action in ('Diagnose', 'ExitVM'): + if dump_on_error is None: + res.append(prefix + 'DumpOnError=true') + dump_on_error = 'true' + + # Add ShowDumpFiles=true if absent from vmargs and DumpOnError=true. + if dump_on_error == 'true': + show_dump_files = _get_graal_option(vmargs, 'ShowDumpFiles', prefix=prefix) + if show_dump_files is None: + res.append(prefix + 'ShowDumpFiles=true') + return res def _gate_dacapo(name, iterations, extraVMarguments=None, force_serial_gc=True, set_start_heap_size=True, threads=None): if iterations == -1: @@ -381,11 +412,16 @@ def _gate_dacapo(name, iterations, extraVMarguments=None, force_serial_gc=True, vmargs = ['-XX:+UseSerialGC'] if force_serial_gc else [] if set_start_heap_size: vmargs += ['-Xms2g'] - vmargs += ['-XX:-UseCompressedOops', '-Djava.net.preferIPv4Stack=true', '-Dgraal.CompilationFailureAction=ExitVM'] + _remove_empty_entries(extraVMarguments) + vmargs += ['-XX:-UseCompressedOops', '-Djava.net.preferIPv4Stack=true'] + _compiler_error_options() + _remove_empty_entries(extraVMarguments) args = ['-n', str(iterations), '--preserve'] if threads is not None: args += ['-t', str(threads)] - return mx_benchmark.gate_mx_benchmark(["dacapo:{}".format(name), "--tracker=none", "--"] + vmargs + ["--"] + args) + out = mx.TeeOutputCapture(mx.OutputCapture()) + exit_code, suite, results = mx_benchmark.gate_mx_benchmark(["dacapo:{}".format(name), "--tracker=none", "--"] + vmargs + ["--"] + args, out=out, err=out, nonZeroIsFatal=False) + if exit_code != 0: + mx.log(out) + mx.abort("Gate for dacapo benchmark '{}' failed!".format(name)) + return exit_code, suite, results def jdk_includes_corba(jdk): # corba has been removed since JDK11 (http://openjdk.java.net/jeps/320) @@ -394,12 +430,64 @@ def jdk_includes_corba(jdk): def _gate_scala_dacapo(name, iterations, extraVMarguments=None): if iterations == -1: return - vmargs = ['-Xms2g', '-XX:+UseSerialGC', '-XX:-UseCompressedOops', '-Dgraal.CompilationFailureAction=ExitVM'] + _remove_empty_entries(extraVMarguments) + vmargs = ['-Xms2g', '-XX:+UseSerialGC', '-XX:-UseCompressedOops'] + _compiler_error_options() + _remove_empty_entries(extraVMarguments) args = ['-n', str(iterations), '--preserve'] - return mx_benchmark.gate_mx_benchmark(["scala-dacapo:{}".format(name), "--tracker=none", "--"] + vmargs + ["--"] + args) + out = mx.TeeOutputCapture(mx.OutputCapture()) + exit_code, suite, results = mx_benchmark.gate_mx_benchmark(["scala-dacapo:{}".format(name), "--tracker=none", "--"] + vmargs + ["--"] + args, out=out, err=out, nonZeroIsFatal=False) + if exit_code != 0: + mx.log(out) + mx.abort("Gate for scala-dacapo benchmark '{}' failed!".format(name)) + return exit_code, suite, results + +def _check_catch_files(): + """ + Verifies that there is a "catch_files" array in common.json at the root of + the repository containing this suite and that the array contains elements + matching DebugContext.DUMP_FILE_MESSAGE_REGEXP and + StandardPathUtilitiesProvider.DIAGNOSTIC_OUTPUT_DIRECTORY_MESSAGE_REGEXP. + """ + catch_files_fields = ( + ('DebugContext', 'DUMP_FILE_MESSAGE_REGEXP'), + ('StandardPathUtilitiesProvider', 'DIAGNOSTIC_OUTPUT_DIRECTORY_MESSAGE_REGEXP') + ) + + def get_regexp(class_name, field_name): + source_path = join(_suite.dir, 'src', 'org.graalvm.compiler.debug', 'src', 'org', 'graalvm', 'compiler', 'debug', class_name + '.java') + regexp = None + with open(source_path) as fp: + for line in fp.readlines(): + decl = field_name + ' = "' + index = line.find(decl) + if index != -1: + start_index = index + len(decl) + end_index = line.find('"', start_index) + regexp = line[start_index:end_index] + + # Convert from Java style regexp to Python style + return regexp.replace('(?<', '(?P<') + + if not regexp: + mx.abort('Could not find value of ' + field_name + ' in ' + source_path) + return regexp + + common_path = join(dirname(_suite.dir), 'common.json') + if not exists(common_path): + mx.abort('Required file does not exist: {}'.format(common_path)) + with open(common_path) as common_file: + common_cfg = json.load(common_file) + catch_files = common_cfg.get('catch_files') + if catch_files is None: + mx.abort('Could not find catch_files attribute in {}'.format(common_path)) + for class_name, field_name in catch_files_fields: + regexp = get_regexp(class_name, field_name) + if regexp not in catch_files: + mx.abort('Could not find catch_files entry in {} matching "{}"'.format(common_path, regexp)) def compiler_gate_runner(suites, unit_test_runs, bootstrap_tests, tasks, extraVMarguments=None, extraUnitTestArguments=None): + with Task('CheckCatchFiles', tasks, tags=[Tags.style]) as t: + if t: _check_catch_files() + if jdk.javaCompliance >= '9': with Task('JDK_java_base_test', tasks, tags=['javabasetest']) as t: if t: java_base_unittest(_remove_empty_entries(extraVMarguments) + []) @@ -426,21 +514,12 @@ def compiler_gate_runner(suites, unit_test_runs, bootstrap_tests, tasks, extraVM ] UnitTestRun('XcompUnitTests', [], tags=GraalTags.test).run(['compiler'], tasks, ['-Xcomp', '-XX:-UseJVMCICompiler'] + _remove_empty_entries(extraVMarguments) + xcompTests) - # Ensure makegraaljdk works - with Task('MakeGraalJDK', tasks, tags=GraalTags.test) as t: - if t: - ws = mx.ensure_dir_exists('MakeGraalJDK-ws') - graaljdk = join(ws, 'graaljdk-' + str(jdk.javaCompliance)) - try: - makegraaljdk_cli(['-a', join(ws, 'graaljdk-' + str(jdk.javaCompliance) + '.tar'), '-b', graaljdk]) - finally: - mx.rmtree(ws) - # Run ctw against rt.jar on hosted with Task('CTW:hosted', tasks, tags=GraalTags.ctw) as t: if t: ctw([ - '-DCompileTheWorld.Config=Inline=false CompilationFailureAction=ExitVM CompilationBailoutAsFailure=false', '-esa', '-XX:-UseJVMCICompiler', '-XX:+EnableJVMCI', + '-DCompileTheWorld.Config=Inline=false CompilationBailoutAsFailure=false ' + ' '.join(_compiler_error_options(prefix='')), + '-esa', '-XX:-UseJVMCICompiler', '-XX:+EnableJVMCI', '-DCompileTheWorld.MultiThreaded=true', '-Dgraal.InlineDuringParsing=false', '-Dgraal.TrackNodeSourcePosition=true', '-DCompileTheWorld.Verbose=false', '-XX:ReservedCodeCacheSize=300m', ], _remove_empty_entries(extraVMarguments)) @@ -466,6 +545,9 @@ def compiler_gate_benchmark_runner(tasks, extraVMarguments=None, prefix=''): # A few iterations to increase the chance of catching compilation errors default_iterations = 2 + bmSuiteArgs = ["--jvm", "server"] + benchVmArgs = bmSuiteArgs + _remove_empty_entries(extraVMarguments) + dacapo_suite = mx_graal_benchmark.DaCapoBenchmarkSuite() dacapo_gate_iterations = { k: default_iterations for k, v in dacapo_suite.daCapoIterations().items() if v > 0 @@ -473,12 +555,10 @@ def compiler_gate_benchmark_runner(tasks, extraVMarguments=None, prefix=''): dacapo_gate_iterations.update({'fop': 8}) mx.warn("Disabling gate for dacapo:tradesoap (GR-33605)") dacapo_gate_iterations.update({'tradesoap': -1}) - for name, iterations in sorted(dacapo_gate_iterations.items()): - if name == "batik" and not _is_batik_supported(jdk): - continue + for name in dacapo_suite.benchmarkList(bmSuiteArgs): + iterations = dacapo_gate_iterations.get(name, -1) with Task(prefix + 'DaCapo:' + name, tasks, tags=GraalTags.benchmarktest) as t: - if t: _gate_dacapo(name, iterations, _remove_empty_entries(extraVMarguments) + - ['-Dgraal.TrackNodeSourcePosition=true'] + dacapo_esa) + if t: _gate_dacapo(name, iterations, benchVmArgs + ['-Dgraal.TrackNodeSourcePosition=true'] + dacapo_esa) # run Scala DaCapo benchmarks # ############################### @@ -486,31 +566,40 @@ def compiler_gate_benchmark_runner(tasks, extraVMarguments=None, prefix=''): scala_dacapo_gate_iterations = { k: default_iterations for k, v in scala_dacapo_suite.daCapoIterations().items() if v > 0 } - - for name, iterations in sorted(scala_dacapo_gate_iterations.items()): + for name in scala_dacapo_suite.benchmarkList(bmSuiteArgs): + iterations = scala_dacapo_gate_iterations.get(name, -1) with Task(prefix + 'ScalaDaCapo:' + name, tasks, tags=GraalTags.benchmarktest) as t: - if t: _gate_scala_dacapo(name, iterations, _remove_empty_entries(extraVMarguments) + - ['-Dgraal.TrackNodeSourcePosition=true'] + dacapo_esa) + if t: _gate_scala_dacapo(name, iterations, benchVmArgs + ['-Dgraal.TrackNodeSourcePosition=true'] + dacapo_esa) # run benchmark with non default setup # ######################################## # ensure -Xbatch still works with Task(prefix + 'DaCapo_pmd:BatchMode', tasks, tags=GraalTags.test) as t: - if t: _gate_dacapo('pmd', 1, _remove_empty_entries(extraVMarguments) + ['-Xbatch']) + if t: _gate_dacapo('pmd', 1, benchVmArgs + ['-Xbatch']) - # ensure benchmark counters still work - if mx.get_arch() != 'aarch64': # GR-8364 Exclude benchmark counters on AArch64 + # ensure benchmark counters still work but omit this test on + # fastdebug as benchmark counter threads may not produce + # output in a timely manner + out = mx.OutputCapture() + mx.run([jdk.java, '-version'], err=subprocess.STDOUT, out=out) + if 'fastdebug' not in out.data and mx.get_arch() != 'aarch64': # GR-34759 with Task(prefix + 'DaCapo_pmd:BenchmarkCounters', tasks, tags=GraalTags.test) as t: if t: fd, logFile = tempfile.mkstemp() os.close(fd) # Don't leak file descriptors try: - _gate_dacapo('pmd', default_iterations, _remove_empty_entries(extraVMarguments) + ['-Dgraal.LogFile=' + logFile, '-Dgraal.LIRProfileMoves=true', '-Dgraal.GenericDynamicCounters=true', '-Dgraal.TimedDynamicCounters=1000', '-XX:JVMCICounterSize=10']) + _gate_dacapo('pmd', default_iterations, benchVmArgs + ['-Dgraal.LogFile=' + logFile, '-Dgraal.LIRProfileMoves=true', '-Dgraal.GenericDynamicCounters=true', '-Dgraal.TimedDynamicCounters=1000', '-XX:JVMCICounterSize=10']) with open(logFile) as fp: haystack = fp.read() needle = 'MoveOperations (dynamic counters)' if needle not in haystack: mx.abort('Expected to see "' + needle + '" in output of length ' + str(len(haystack)) + ':\n' + haystack) + except BaseException: + with open(logFile) as fp: + haystack = fp.read() + if haystack: + mx.log(haystack) + raise finally: os.remove(logFile) @@ -520,24 +609,24 @@ def compiler_gate_benchmark_runner(tasks, extraVMarguments=None, prefix=''): # ensure -XX:+PreserveFramePointer still works with Task(prefix + 'DaCapo_pmd:PreserveFramePointer', tasks, tags=GraalTags.test) as t: - if t: _gate_dacapo('pmd', default_iterations, _remove_empty_entries(extraVMarguments) + ['-Xmx256M', '-XX:+PreserveFramePointer'], threads=4, force_serial_gc=False, set_start_heap_size=False) + if t: _gate_dacapo('pmd', default_iterations, benchVmArgs + ['-Xmx256M', '-XX:+PreserveFramePointer'], threads=4, force_serial_gc=False, set_start_heap_size=False) if isJDK8: # temporarily isolate those test (GR-10990) cms = ['cms'] # ensure CMS still works with Task(prefix + 'DaCapo_pmd:CMS', tasks, tags=cms) as t: - if t: _gate_dacapo('pmd', default_iterations, _remove_empty_entries(extraVMarguments) + ['-Xmx256M', '-XX:+UseConcMarkSweepGC'], threads=4, force_serial_gc=False, set_start_heap_size=False) + if t: _gate_dacapo('pmd', default_iterations, benchVmArgs + ['-Xmx256M', '-XX:+UseConcMarkSweepGC'], threads=4, force_serial_gc=False, set_start_heap_size=False) # ensure CMSIncrementalMode still works with Task(prefix + 'DaCapo_pmd:CMSIncrementalMode', tasks, tags=cms) as t: - if t: _gate_dacapo('pmd', default_iterations, _remove_empty_entries(extraVMarguments) + ['-Xmx256M', '-XX:+UseConcMarkSweepGC', '-XX:+CMSIncrementalMode'], threads=4, force_serial_gc=False, set_start_heap_size=False) + if t: _gate_dacapo('pmd', default_iterations, benchVmArgs + ['-Xmx256M', '-XX:+UseConcMarkSweepGC', '-XX:+CMSIncrementalMode'], threads=4, force_serial_gc=False, set_start_heap_size=False) if prefix != '': # ensure G1 still works with libgraal with Task(prefix + 'DaCapo_pmd:G1', tasks, tags=cms) as t: - if t: _gate_dacapo('pmd', default_iterations, _remove_empty_entries(extraVMarguments) + ['-Xmx256M', '-XX:+UseG1GC'], threads=4, force_serial_gc=False, set_start_heap_size=False) + if t: _gate_dacapo('pmd', default_iterations, benchVmArgs + ['-Xmx256M', '-XX:+UseG1GC'], threads=4, force_serial_gc=False, set_start_heap_size=False) @@ -554,7 +643,7 @@ def compiler_gate_benchmark_runner(tasks, extraVMarguments=None, prefix=''): _defaultFlags = ['-Dgraal.CompilationWatchDogStartDelay=60.0D'] _assertionFlags = ['-esa', '-Dgraal.DetailedAsserts=true'] -_graalErrorFlags = ['-Dgraal.CompilationFailureAction=ExitVM'] +_graalErrorFlags = _compiler_error_options() _graalEconomyFlags = ['-Dgraal.CompilerConfiguration=economy'] _verificationFlags = ['-Dgraal.VerifyGraalGraphs=true', '-Dgraal.VerifyGraalGraphEdges=true', '-Dgraal.VerifyGraalPhasesSize=true', '-Dgraal.VerifyPhases=true'] _coopFlags = ['-XX:-UseCompressedOops'] @@ -562,7 +651,6 @@ def compiler_gate_benchmark_runner(tasks, extraVMarguments=None, prefix=''): _g1VerificationFlags = ['-XX:-UseSerialGC', '-XX:+UseG1GC'] _exceptionFlags = ['-Dgraal.StressInvokeWithExceptionNode=true'] _registerPressureFlags = ['-Dgraal.RegisterPressure=' + _registers[mx.get_arch()]] -_immutableCodeFlags = ['-Dgraal.ImmutableCode=true'] graal_bootstrap_tests = [ BootstrapTest('BootstrapWithSystemAssertionsFullVerify', _defaultFlags + _assertionFlags + _verificationFlags + _graalErrorFlags, tags=GraalTags.bootstrapfullverify), @@ -573,7 +661,6 @@ def compiler_gate_benchmark_runner(tasks, extraVMarguments=None, prefix=''): BootstrapTest('BootstrapWithSystemAssertionsEconomy', _defaultFlags + _assertionFlags + _graalEconomyFlags + _graalErrorFlags, tags=GraalTags.bootstrap), BootstrapTest('BootstrapWithSystemAssertionsExceptionEdges', _defaultFlags + _assertionFlags + _exceptionFlags + _graalErrorFlags, tags=GraalTags.bootstrap), BootstrapTest('BootstrapWithSystemAssertionsRegisterPressure', _defaultFlags + _assertionFlags + _registerPressureFlags + _graalErrorFlags, tags=GraalTags.bootstrap), - BootstrapTest('BootstrapWithSystemAssertionsImmutableCode', _defaultFlags + _assertionFlags + _immutableCodeFlags + ['-Dgraal.VerifyPhases=true'] + _graalErrorFlags, tags=GraalTags.bootstrap) ] def _graal_gate_runner(args, tasks): @@ -643,10 +730,16 @@ def _unittest_config_participant(config): # ALL-UNNAMED. mainClassArgs.extend(['-JUnitOpenPackages', 'jdk.internal.vm.ci/*=jdk.internal.vm.compiler,ALL-UNNAMED']) + limited_modules = None + for arg in vmArgs: + if arg.startswith('--limit-modules'): + assert arg.startswith('--limit-modules='), ('--limit-modules must be separated from its value by "="') + limited_modules = arg[len('--limit-modules='):].split(',') + # Export packages in all Graal modules and their dependencies for dist in _graal_config().dists: jmd = as_java_module(dist, jdk) - if _graaljdk_override is None or jmd in _graaljdk_override.get_modules(): + if limited_modules is None or jmd.name in limited_modules: mainClassArgs.extend(['-JUnitOpenPackages', jmd.name + '/*']) vmArgs.append('--add-modules=' + jmd.name) @@ -671,6 +764,7 @@ def _unittest_config_participant(config): # TODO: GR-31197, this should be removed. vmArgs.append('-Dpolyglot.engine.DynamicCompilationThresholds=false') vmArgs.append('-Dpolyglot.engine.AllowExperimentalOptions=true') + return (vmArgs, mainClass, mainClassArgs) mx_unittest.add_config_participant(_unittest_config_participant) @@ -725,8 +819,7 @@ def _parseVmArgs(args, addDefaultArgs=True): # The default for CompilationFailureAction in the code is Silent as this is # what we want for GraalVM. When using Graal via mx (e.g. in the CI gates) # Diagnose is a more useful "default" value. - if not any(a.startswith('-Dgraal.CompilationFailureAction=') for a in args): - argsPrefix.append('-Dgraal.CompilationFailureAction=Diagnose') + argsPrefix.extend(_compiler_error_options('Diagnose', args)) # It is safe to assume that Network dumping is the desired default when using mx. # Mx is never used in production environments. @@ -737,6 +830,29 @@ def _parseVmArgs(args, addDefaultArgs=True): if not any(a.startswith('-Dgraal.ObjdumpExecutables=') for a in args): argsPrefix.append('-Dgraal.ObjdumpExecutables=objdump,gobjdump') + # The GraalVM locator must be disabled so that Truffle languages + # are loaded from the class path. This is the configuration expected + # by the unit tests and benchmarks run via the compiler suite. + if not any(a.startswith('-Dgraalvm.locatorDisabled=') for a in args): + argsPrefix.append('-Dgraalvm.locatorDisabled=true') + + # On JDK8 running a GraalJDK requires putting Truffle and all components + # that have boot jars on the boot class path. + if isJDK8: + new_args = [] + bcpa = [] + # Filter out all instances of -Xbootclasspath/a: from args, keeping + # the last, if any. + for a in args: + if a.startswith('-Xbootclasspath/a:'): + bcpa = a[len('-Xbootclasspath/a:'):].split(os.pathsep) + else: + new_args.append(a) + gc = _graal_config() + bcpa = [bj for bj in gc.boot_jars if basename(bj) != 'graal-sdk.jar'] + gc.truffle_jars + bcpa + argsPrefix.append('-Xbootclasspath/a:' + os.pathsep.join(bcpa)) + args = new_args + return argsPrefix + args def _check_bootstrap_config(args): @@ -810,23 +926,46 @@ def __exit__(self, exc_type, exc_value, traceback): finally: os.remove(tmp_file) -_graaljdk_override = None +def _graaljdk_dist(edition=None): + """ + Gets the GraalJDK distribution specified by `edition`. + A GraalJDK is a fixed GraalVM configuration specified by the `cmp_ce_components` field. -def _graaljdk_home(base_name): - graaljdks = [d for d in mx.sorted_dists() if isinstance(d, mx_sdk_vm_impl.GraalVmLayoutDistribution) and d.base_name == base_name] + :param str edition: 'ce', 'ee' or None. If None, then an EE GraalJDK is returned if available otherwise a CE GraalJDK. + """ + candidates = [d for d in mx.sorted_dists() if isinstance(d, mx_sdk_vm_impl.GraalVmLayoutDistribution)] + if edition is None: + graaljdks = [d for d in candidates if d.base_name == 'GraalJDK_EE'] + if graaljdks: + base_name = 'GraalJDK_EE' + else: + graaljdks = [d for d in candidates if d.base_name == 'GraalJDK_CE'] + if graaljdks: + base_name = 'GraalJDK_CE' + else: + mx.abort("Cannot find any GraalJDK images") + else: + assert edition in ('ce', 'ee'), edition + base_name = 'GraalJDK_{}'.format(edition.upper()) + graaljdks = [d for d in candidates if d.base_name == base_name] if not graaljdks: - raise mx.abort("Cannot find GraalJDK images with base name '{}'".format(base_name)) + raise mx.abort("Cannot find GraalJDK image with base name '{}'".format(base_name)) if len(graaljdks) > 1: raise mx.abort("Found multiple GraalJDKs with the same base name '{}'".format(base_name)) - return join(graaljdks[0].output, graaljdks[0].jdk_base) + return graaljdks[0] -def get_graaljdk(): - if _graaljdk_override is None: - graaljdk_dir, _ = _update_graaljdk(jdk) - graaljdk = mx.JDKConfig(graaljdk_dir) - else: - graaljdk = _graaljdk_override - return graaljdk +def _graaljdk_home(edition=None): + """ + Gets the JAVA_HOME directory for the GraalJDK distribution (see _graaljdk_dist above). + """ + graaljdk_dist = _graaljdk_dist(edition) + return join(graaljdk_dist.output, graaljdk_dist.jdk_base) + +def get_graaljdk(edition=None): + graaljdk_dir = _graaljdk_home(edition) + if not exists(graaljdk_dir): + mx.abort('{} does not exist - forgot to run `mx build`?'.format(graaljdk_dir)) + return mx.JDKConfig(graaljdk_dir) def collate_metrics(args): """ @@ -899,9 +1038,6 @@ def run_java(args, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=No graaljdk = get_graaljdk() vm_args = _parseVmArgs(args, addDefaultArgs=addDefaultArgs) args = ['-XX:+UnlockExperimentalVMOptions', '-XX:+EnableJVMCI'] + vm_args - add_exports = join(graaljdk.home, '.add_exports') - if exists(add_exports): - args = ['@' + add_exports] + args _check_bootstrap_config(args) cmd = get_vm_prefix() + [graaljdk.java] + ['-server'] + args map_file = join(graaljdk.home, 'proguard.map') @@ -1078,28 +1214,21 @@ def sl(args): def java_base_unittest(args): """tests whether the Graal compiler runs on a JDK with a minimal set of modules""" - global _graaljdk_override - try: - # Remove GRAAL_MANAGEMENT from the module path as it - # depends on the java.management module which is not in - # the limited module set - base_modules = ['java.base', 'java.logging', 'jdk.internal.vm.ci', 'jdk.unsupported', 'jdk.compiler'] - compiler_modules = [as_java_module(d, jdk).name for d in _graal_config().dists if d.name != 'GRAAL_MANAGEMENT'] - root_module_names = base_modules + compiler_modules - graaljdk_dir, _ = _update_graaljdk(jdk, root_module_names=root_module_names) - _graaljdk_override = mx.JDKConfig(graaljdk_dir) - - if mx_gate.Task.verbose: - extra_args = ['--verbose', '--enable-timing'] - else: - extra_args = [] - # the base JDK doesn't include jdwp - if _graaljdk_override.debug_args: - mx.warn('Ignoring Java debugger arguments because base JDK doesn\'t include jdwp') - with mx.DisableJavaDebugging(): - mx_unittest.unittest(['--suite', 'compiler', '--fail-fast'] + extra_args + args) - finally: - _graaljdk_override = None + # Remove GRAAL_MANAGEMENT from the module path as it + # depends on the java.management module which is not in + # the limited module set + base_modules = ['java.base', 'java.logging', 'jdk.internal.vm.ci', 'jdk.unsupported', 'jdk.compiler'] + compiler_modules = [as_java_module(d, jdk).name for d in _graal_config().dists if d.name != 'GRAAL_MANAGEMENT'] + root_module_names = base_modules + compiler_modules + extra_args = ['--limit-modules=' + ','.join(root_module_names)] + + if mx_gate.Task.verbose: + extra_args.extend(['--verbose', '--enable-timing']) + # the base JDK doesn't include jdwp + if get_graaljdk().debug_args: + mx.warn('Ignoring Java debugger arguments because base JDK doesn\'t include jdwp') + with mx.DisableJavaDebugging(): + mx_unittest.unittest(['--suite', 'compiler', '--fail-fast'] + extra_args + args) def javadoc(args): # metadata package was deprecated, exclude it @@ -1149,248 +1278,9 @@ def _zipadd(arc, filename, arcname): arc.close() -def _jlink_libraries(): - return not (mx.get_opts().no_jlinking or mx.env_var_to_bool('NO_JLINKING')) - def makegraaljdk_cli(args): """make a JDK with Graal as the default top level JIT""" - parser = ArgumentParser(prog='mx makegraaljdk') - parser.add_argument('-f', '--force', action='store_true', help='overwrite existing GraalJDK') - parser.add_argument('-a', '--archive', action='store', help='name of archive to create', metavar='') - parser.add_argument('-b', '--bootstrap', action='store_true', help='execute a bootstrap of the created GraalJDK') - parser.add_argument('-l', '--license', action='store', help='path to the license file', metavar='') - parser.add_argument('-o', '--overlay', action='store_true', help='Only write the Graal files into the destination') - parser.add_argument('dest', help='destination directory for GraalJDK', metavar='') - args = parser.parse_args(args) - - if args.overlay and not isJDK8: - mx.abort('The --overlay option is only supported on JDK 8') - - dst_jdk_dir = os.path.abspath(args.dest) - if exists(dst_jdk_dir): - if args.force: - shutil.rmtree(dst_jdk_dir) - - _, updated = _update_graaljdk(jdk, dst_jdk_dir, export_truffle=False, with_compiler_name_file=True) - dst_jdk = mx.JDKConfig(dst_jdk_dir) - if not updated: - mx.log(dst_jdk_dir + ' is already up to date') - - if args.license: - shutil.copy(args.license, join(dst_jdk_dir, 'LICENSE')) - if args.bootstrap: - map_file = join(dst_jdk_dir, 'proguard.map') - with StdoutUnstripping(args=[], out=None, err=None, mapFiles=[map_file]) as u: - # Just use a set of flags that will work on all JVMCI enabled VMs without trying - # to remove flags that are unnecessary for a specific VM. - mx.run([dst_jdk.java, '-XX:+UnlockExperimentalVMOptions', '-XX:+UseJVMCICompiler', '-XX:+BootstrapJVMCI', '-version'], out=u.out, err=u.err) - if args.archive: - mx.log('Archiving {}'.format(args.archive)) - create_archive(dst_jdk_dir, args.archive, basename(args.dest) + '/') - -def _update_graaljdk(src_jdk, dst_jdk_dir=None, root_module_names=None, export_truffle=True, with_compiler_name_file=False): - """ - Creates or updates a GraalJDK in `dst_jdk_dir` from `src_jdk`. - - :param str dst_jdk_dir: path where GraalJDK is (to be) located. If None, then a path name is - derived based on _graalvm_components and `root_module_names`. - :param list root_module_names: names of modules in the root set for the new JDK image. If None, - the root set is derived from _graalvm_components. - :param bool export_truffle: specifies if Truffle API packages should be visible to the app class loader. - On JDK 8, this causes Truffle to be on the boot class path. On JDK 9+, this results - in a ``.add_exports`` file in `dst_dst_dir` which can be used as an @argfile VM argument. - :param bool with_compiler_name_file: if True, a ``compiler-name`` file is written in the ``jvmci`` directory under - `dst_jdk_dir`. Depending on `src_jdk`, the existence of this file can set the - value of UseJVMCICompiler be true. For example, see - https://github.com/graalvm/graal-jvmci-8/blob/master/src/share/vm/jvmci/jvmci_globals.hpp#L52 - :return: a tuple containing the path where the GraalJDK is located and a boolean denoting whether - the GraalJDK was update/created (True) or was already up to date (False) - - """ - update_reason = None - if dst_jdk_dir is None: - graaljdks_dir = mx.ensure_dir_exists(join(_suite.get_output_root(platformDependent=True), 'graaljdks')) - graalvm_compiler_short_names = [c.short_name for c in mx_sdk_vm.graalvm_components() if isinstance(c, mx_sdk_vm.GraalVmJvmciComponent) and c.graal_compiler] - jdk_suffix = '-'.join(graalvm_compiler_short_names) - if root_module_names: - jdk_suffix += '-' + hashlib.sha1(_encode(','.join(root_module_names))).hexdigest() - if mx.get_opts().strip_jars: - jdk_suffix += '-stripped' - dst_jdk_dir = join(graaljdks_dir, 'jdk{}-{}'.format(src_jdk.javaCompliance, jdk_suffix)) - if dst_jdk_dir == src_jdk.home: - # Avoid overwriting source JDK - dst_jdk_dir += '_new' - else: - if dst_jdk_dir == src_jdk.home: - mx.abort("Cannot overwrite source JDK: {}".format(src_jdk)) - - # When co-developing JVMCI/JDK changes with Graal, the source JDK - # may have changed and we want to pick up these changes. - source_jdk_timestamps_file = dst_jdk_dir + '.source_jdk_timestamps' - timestamps = [] - nl = '\n' - for root, _, filenames in os.walk(jdk.home): - for name in filenames: - ts = mx.TimeStampFile(join(root, name)) - timestamps.append(str(ts)) - timestamps = sorted(timestamps) - jdk_timestamps = jdk.home + nl + nl.join(timestamps) - jdk_timestamps_outdated = False - if exists(source_jdk_timestamps_file): - with open(source_jdk_timestamps_file) as fp: - old_jdk_timestamps = fp.read() - if old_jdk_timestamps != jdk_timestamps: - jdk_timestamps_outdated = True - old_jdk_home = old_jdk_timestamps.split(nl, 1)[0] - if old_jdk_home == jdk.home: - import difflib - old_timestamps = old_jdk_timestamps.split(nl) - diff = difflib.unified_diff(timestamps, old_timestamps, 'new_timestamps.txt', 'old_timestamps.txt') - update_reason = 'source JDK was updated as shown by following time stamps diff:{}{}'.format(nl, nl.join(diff)) - else: - update_reason = 'source JDK was changed from {} to {}'.format(old_jdk_home, jdk.home) - else: - jdk_timestamps_outdated = True - - if jdk_timestamps_outdated: - with mx.SafeFileCreation(source_jdk_timestamps_file) as sfc: - with open(sfc.tmpPath, 'w') as fp: - fp.write(jdk_timestamps) - - jvmci_release_file = mx.TimeStampFile(join(dst_jdk_dir, 'release.jvmci')) - if update_reason is None: - if not exists(dst_jdk_dir): - update_reason = dst_jdk_dir + ' does not exist' - else: - newer = [e for e in _graal_config().jars if jvmci_release_file.isOlderThan(e)] - if newer: - update_reason = '{} is older than {}'.format(jvmci_release_file, mx.TimeStampFile(newer[0])) - - if update_reason is None: - return dst_jdk_dir, False - - with SafeDirectoryUpdater(dst_jdk_dir) as sdu: - tmp_dst_jdk_dir = sdu.directory - mx.log('Updating/creating {} from {} using intermediate directory {} since {}'.format(dst_jdk_dir, src_jdk.home, tmp_dst_jdk_dir, update_reason)) - def _copy_file(src, dst): - mx.log('Copying {} to {}'.format(src, dst)) - if mx.can_symlink(): - if exists(dst) and islink(dst): - os.remove(dst) - os.symlink(src, dst) - else: - shutil.copyfile(src, dst) - - vm_name = 'Server VM Graal' - for d in _graal_config().jvmci_dists: - version = d.suite.version() - s = ':' + d.suite.name - if version: - s += '_' + d.suite.version() - if s not in vm_name: - vm_name = vm_name + s - - if isJDK8: - jre_dir = join(tmp_dst_jdk_dir, 'jre') - shutil.copytree(src_jdk.home, tmp_dst_jdk_dir) - - boot_dir = mx.ensure_dir_exists(join(jre_dir, 'lib', 'boot')) - jvmci_dir = mx.ensure_dir_exists(join(jre_dir, 'lib', 'jvmci')) - - for src_jar in _graal_config().jvmci_jars: - _copy_file(src_jar, join(jvmci_dir, basename(src_jar))) - - boot_jars = _graal_config().boot_jars - if not export_truffle: - truffle_dir = mx.ensure_dir_exists(join(jre_dir, 'lib', 'truffle')) - for src_jar in _graal_config().truffle_jars: - _copy_file(src_jar, join(truffle_dir, basename(src_jar))) - for jvmci_parent_jar in _graal_config().jvmci_parent_jars: - with open(join(jvmci_dir, 'parentClassLoader.classpath'), 'w') as fp: - fp.write(join('..', 'truffle', basename(jvmci_parent_jar))) - else: - boot_jars += _graal_config().jvmci_parent_jars - - for src_jar in boot_jars: - dst_jar = join(boot_dir, basename(src_jar)) - _copy_file(src_jar, dst_jar) - - else: - module_dists = _graal_config().dists - _check_using_latest_jars(module_dists) - vendor_info = {'vendor-version' : vm_name} - # Setting dedup_legal_notices=False avoids due to license files conflicting - # when switching JAVA_HOME from an OpenJDK to an OracleJDK or vice versa between executions. - if _jlink_libraries(): - jlink_new_jdk(jdk, tmp_dst_jdk_dir, module_dists, ignore_dists=[], root_module_names=root_module_names, vendor_info=vendor_info, dedup_legal_notices=False) - if export_truffle: - jmd = as_java_module(_graal_config().dists_dict['truffle:TRUFFLE_API'], jdk) - add_exports = [] - for package in jmd.packages: - if package == 'com.oracle.truffle.api.impl': - # The impl package should remain private - continue - if jmd.get_package_visibility(package, "") == 'concealed': - add_exports.append('--add-exports={}/{}=ALL-UNNAMED'.format(jmd.name, package)) - if add_exports: - with open(join(tmp_dst_jdk_dir, '.add_exports'), 'w') as fp: - fp.write(os.linesep.join(add_exports)) - else: - mx.warn("--no-jlinking flag used. The resulting VM will be HotSpot, not GraalVM") - shutil.copytree(jdk.home, tmp_dst_jdk_dir, symlinks=True) - jre_dir = tmp_dst_jdk_dir - jvmci_dir = mx.ensure_dir_exists(join(jre_dir, 'lib', 'jvmci')) - - if with_compiler_name_file: - with open(join(jvmci_dir, 'compiler-name'), 'w') as fp: - print('graal', file=fp) - - if jdk.javaCompliance < '9' and mx.get_os() not in ['darwin', 'windows']: - # On JDK 8, the server directory containing the JVM library is - # in an architecture specific directory (except for Darwin and Windows). - libjvm_dir = join(jre_dir, 'lib', mx.get_arch(), 'server') - elif mx.get_os() == 'windows': - libjvm_dir = join(jre_dir, 'bin', 'server') - else: - libjvm_dir = join(jre_dir, 'lib', 'server') - mx.ensure_dir_exists(libjvm_dir) - jvmlib = join(libjvm_dir, mx.add_lib_prefix(mx.add_lib_suffix('jvm'))) - - with open(join(tmp_dst_jdk_dir, 'release.jvmci'), 'w') as fp: - for d in _graal_config().jvmci_dists: - s = d.suite - if s.vc: - print('{}={}'.format(d.name, s.vc.parent(s.dir)), file=fp) - for d in _graal_config().boot_dists + _graal_config().truffle_dists: - s = d.suite - if s.vc: - print('{}={}'.format(d.name, s.vc.parent(s.dir)), file=fp) - - assert exists(jvmlib), jvmlib + ' does not exist' - out = mx.LinesOutputCapture() - mx.run([jdk.java, '-version'], err=out) - line = None - pattern = re.compile(r'(.* )(?:Server|Graal) VM .*\((?:.+ )?build.*') - for line in out.lines: - m = pattern.match(line) - if m: - with io.open(join(libjvm_dir, 'vm.properties'), 'w', newline='') as fp: - # Modify VM name in `java -version` to be Graal along - # with a suffix denoting the commit of each Graal jar. - # For example: - # Java HotSpot(TM) 64-Bit Graal:compiler_88847fb25d1a62977a178331a5e78fa5f8fcbb1a (build 25.71-b01-internal-jvmci-0.34, mixed mode) - print(u'name=' + m.group(1) + vm_name, file=fp) - line = True - break - if line is not True: - mx.abort('Could not find "{}" in output of `java -version`:\n{}'.format(pattern.pattern, os.linesep.join(out.lines))) - - unstrip_map = mx.make_unstrip_map(_graal_config().dists) - if unstrip_map: - with open(join(tmp_dst_jdk_dir, 'proguard.map'), 'w') as fp: - fp.write(unstrip_map) - - return dst_jdk_dir, True + mx.abort('The makegraaljdk command is no longer supported. Use the graaljdk-home command instead.') __graal_config = None @@ -1481,11 +1371,19 @@ def mx_register_dynamic_suite_constituents(register_project, register_distributi graal_jdk_dist.maven = {'groupId': 'org.graalvm', 'tag': 'graaljdk'} register_distribution(graal_jdk_dist) + +def _parse_graaljdk_edition(description, args): + parser = ArgumentParser(description=description) + parser.add_argument('--edition', choices=['ce', 'ee'], default=None, help='GraalJDK CE or EE') + return parser.parse_args(args).edition + def print_graaljdk_home(args): - parser = ArgumentParser(description='Print the GraalJDK home directory') - parser.add_argument('--edition', choices=['ce', 'ee'], default='ce', help='GraalJDK CE or EE') - args = parser.parse_args(args) - print(_graaljdk_home('GraalJDK_{}'.format(args.edition.upper()))) + """print the GraalJDK JAVA_HOME directory""" + print(_graaljdk_home(_parse_graaljdk_edition('Print the GraalJDK JAVA_HOME directory', args))) + +def print_graaljdk_config(args): + """print the GraalJDK config""" + mx_sdk_vm_impl.graalvm_show([], _graaljdk_dist(_parse_graaljdk_edition('Print the GraalJDK config', args))) mx.update_commands(_suite, { 'sl' : [sl, '[SL args|@VM options]'], @@ -1499,6 +1397,7 @@ def print_graaljdk_home(args): 'javadoc': [javadoc, ''], 'makegraaljdk': [makegraaljdk_cli, '[options]'], 'graaljdk-home': [print_graaljdk_home, '[options]'], + 'graaljdk-show': [print_graaljdk_config, '[options]'], }) def mx_post_parse_cmd_line(opts): diff --git a/compiler/mx.compiler/mx_graal_tools.py b/compiler/mx.compiler/mx_graal_tools.py index 7fc38543e848..f4e36ea9955a 100644 --- a/compiler/mx.compiler/mx_graal_tools.py +++ b/compiler/mx.compiler/mx_graal_tools.py @@ -70,13 +70,6 @@ def run_netbeans_app(app_name, env=None, args=None): launch.append('-J-Dnetbeans.logger.console=false') mx.run(launch+args, env=env) -def netbeans_jdk(appName): - v8u20 = mx.VersionSpec("1.8.0_20") - v8u40 = mx.VersionSpec("1.8.0_40") - def _igvJdkVersionCheck(version): - return version < v8u20 or version >= v8u40 - return mx.get_jdk(_igvJdkVersionCheck, versionDescription='(< 1.8.0u20 or >= 1.8.0u40)', purpose="running " + appName).home - def igv(args): """(obsolete) informs about IGV""" mx.warn( @@ -89,9 +82,12 @@ def igv(args): def c1visualizer(args): """run the C1 Compiler Visualizer""" + v8u40 = mx.VersionSpec("1.8.0_40") + def _c1vJdkVersionCheck(version): + return version >= v8u40 and str(version).startswith('1.8.0') env = dict(os.environ) - env['jdkhome'] = netbeans_jdk("C1 Visualizer") - run_netbeans_app('C1Visualizer', env, args) + env['jdkhome'] = mx.get_jdk(_c1vJdkVersionCheck, versionDescription='(1.8 JDK that is >= 1.8.0u40 )', purpose="running C1 Visualizer").home + run_netbeans_app('C1Visualizer', env, args() if callable(args) else args) def hsdis(args, copyToDir=None): """download the hsdis library @@ -165,7 +161,7 @@ def hsdis(args, copyToDir=None): except IOError as e: mx.warn('Could not copy {} to {}: {}'.format(path, dest, str(e))) -def hcfdis(args): +def hcfdis(args, cp=None): """disassemble HexCodeFiles embedded in text files Run a tool over the input files to convert all embedded HexCodeFiles @@ -177,7 +173,7 @@ def hcfdis(args): args = parser.parse_args(args) - path = mx.library('HCFDIS').get_path(resolve=True) + path = cp or mx.library('HCFDIS').get_path(resolve=True) mx.run_java(['-cp', path, 'com.oracle.max.hcfdis.HexCodeFileDis'] + args.files) if args.map is not None: diff --git a/compiler/mx.compiler/suite.py b/compiler/mx.compiler/suite.py index a71c392fd794..46dc86b0d8fa 100644 --- a/compiler/mx.compiler/suite.py +++ b/compiler/mx.compiler/suite.py @@ -4,7 +4,7 @@ "sourceinprojectwhitelist" : [], "groupId" : "org.graalvm.compiler", - "version" : "21.3.0", + "version" : "22.0.0", "release" : False, "url" : "http://www.graalvm.org/", "developer" : { @@ -434,6 +434,7 @@ ], "annotationProcessors" : [ ], + "spotbugs" : "false", "checkstyle" : "org.graalvm.compiler.graph", "javaCompliance" : "8,11+", "workingSets" : "API,Graal", @@ -447,6 +448,7 @@ "org.graalvm.nativebridge.jni", "org.graalvm.libgraal.jni.annotation", "sdk:GRAAL_SDK", + "JVMCI_HOTSPOT", ], "annotationProcessors" : [ "GRAAL_LIBGRAAL_PROCESSOR", @@ -1567,6 +1569,11 @@ "requiresConcealed" : { "jdk.internal.vm.ci" : [ "jdk.vm.ci.meta", + "jdk.vm.ci.code", + ], + "java.base" : [ + "jdk.internal.misc", + "jdk.internal.vm.annotation", ], }, "checkstyle" : "org.graalvm.compiler.graph", @@ -2168,12 +2175,12 @@ "jdk.unsupported" # sun.misc.Unsafe ], "exports" : [ - "* to com.oracle.graal.graal_enterprise,org.graalvm.nativeimage.pointsto,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.llvm,com.oracle.svm.svm_enterprise", + "* to com.oracle.graal.graal_enterprise,org.graalvm.nativeimage.pointsto,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.llvm,com.oracle.svm.svm_enterprise,org.graalvm.nativeimage.base", "org.graalvm.compiler.core.common to jdk.internal.vm.compiler.management,org.graalvm.nativeimage.agent.tracing", "org.graalvm.compiler.debug to jdk.internal.vm.compiler.management,org.graalvm.nativeimage.objectfile", "org.graalvm.compiler.hotspot to jdk.internal.vm.compiler.management", "org.graalvm.compiler.nodes.graphbuilderconf to org.graalvm.nativeimage.driver", - "org.graalvm.compiler.options to jdk.internal.vm.compiler.management,org.graalvm.nativeimage.driver,org.graalvm.nativeimage.librarysupport", + "org.graalvm.compiler.options to jdk.internal.vm.compiler.management,org.graalvm.nativeimage.driver,org.graalvm.nativeimage.junitsupport", "org.graalvm.compiler.phases.common to org.graalvm.nativeimage.agent.tracing,org.graalvm.nativeimage.configure", "org.graalvm.compiler.phases.common.jmx to jdk.internal.vm.compiler.management", "org.graalvm.compiler.serviceprovider to jdk.internal.vm.compiler.management,org.graalvm.nativeimage.driver,org.graalvm.nativeimage.agent.jvmtibase,org.graalvm.nativeimage.agent.diagnostics", diff --git a/compiler/src/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/IterationDirectiveTest.java b/compiler/src/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/IterationDirectiveTest.java index d32454431078..800f0baf3095 100644 --- a/compiler/src/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/IterationDirectiveTest.java +++ b/compiler/src/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/IterationDirectiveTest.java @@ -24,14 +24,14 @@ */ package org.graalvm.compiler.api.directives.test; -import org.junit.Assert; -import org.junit.Test; - import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.graph.iterators.NodeIterable; import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; +import org.junit.Assert; +import org.junit.Test; public class IterationDirectiveTest extends GraalCompilerTest { @@ -59,6 +59,6 @@ protected void checkLowTierGraph(StructuredGraph graph) { Assert.assertEquals("LoopBeginNode count", 1, loopBeginNodes.count()); LoopBeginNode loopBeginNode = loopBeginNodes.first(); - Assert.assertEquals("loop frequency of " + loopBeginNode, 128, loopBeginNode.loopFrequency(), 0); + Assert.assertEquals("loop frequency of " + loopBeginNode, 128, ControlFlowGraph.compute(graph, false, false, false, false).localLoopFrequency(loopBeginNode), 0); } } diff --git a/compiler/src/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java b/compiler/src/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java index bbd6e1dc1d01..ea515df376b1 100644 --- a/compiler/src/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java +++ b/compiler/src/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java @@ -76,8 +76,8 @@ protected void cbz(int size, Register reg, int imm21) { } @Override - protected void b(int imm28) { - super.b(imm28); + protected void b() { + super.b(); } @Override diff --git a/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64ASIMDAssembler.java b/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64ASIMDAssembler.java index aa7caaa48bd3..25870750d06a 100644 --- a/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64ASIMDAssembler.java +++ b/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64ASIMDAssembler.java @@ -2417,9 +2417,8 @@ public void scvtfVV(ASIMDSize size, ElementSize eSize, Register dst, Register sr * for i in 0..n-1 do dst[i] = src[i] << imm * * @param size register size. - * @param eSize element size. Must be ElementSize.Word or ElementSize.DoubleWord. Note - * ElementSize.DoubleWord is only applicable when size is 128 (i.e. the operation is - * performed on more than one element). + * @param eSize element size. ElementSize.DoubleWord is only applicable when size is 128 (i.e. + * the operation is performed on more than one element). * @param dst SIMD register. * @param src SIMD register. * @param shiftAmt shift amount. @@ -2554,9 +2553,8 @@ public void smovGX(ElementSize dstESize, ElementSize srcESize, Register dst, Reg * dst[i] = (src1[i] >> byte(src2[i]) * * @param size register size. - * @param eSize element size. Must be ElementSize.Word or ElementSize.DoubleWord. Note - * ElementSize.DoubleWord is only applicable when size is 128 (i.e. the operation is - * performed on more than one element). + * @param eSize element size. ElementSize.DoubleWord is only applicable when size is 128 (i.e. + * the operation is performed on more than one element). * @param dst SIMD register. * @param src1 SIMD register. * @param src2 SIMD register. @@ -2604,9 +2602,8 @@ public void sshllVVI(ElementSize srcESize, Register dst, Register src, int shift * for i in 0..n-1 do dst[i] = src[i] >> imm * * @param size register size. - * @param eSize element size. Must be ElementSize.Word or ElementSize.DoubleWord. Note - * ElementSize.DoubleWord is only applicable when size is 128 (i.e. the operation is - * performed on more than one element). + * @param eSize element size. ElementSize.DoubleWord is only applicable when size is 128 (i.e. + * the operation is performed on more than one element). * @param dst SIMD register. * @param src SIMD register. * @param shiftAmt shift right amount. @@ -2984,9 +2981,8 @@ public void umovGX(ElementSize eSize, Register dst, Register src, int index) { * dst[i] = (src1[i] >>> byte(src2[i]) * * @param size register size. - * @param eSize element size. Must be ElementSize.Word or ElementSize.DoubleWord. Note - * ElementSize.DoubleWord is only applicable when size is 128 (i.e. the operation is - * performed on more than one element). + * @param eSize element size. ElementSize.DoubleWord is only applicable when size is 128 (i.e. + * the operation is performed on more than one element). * @param dst SIMD register. * @param src1 SIMD register. * @param src2 SIMD register. @@ -3057,9 +3053,8 @@ public void ushrSSI(ElementSize eSize, Register dst, Register src, int shiftAmt) * dst = src >>> imm * * @param size register size. - * @param eSize element size. Must be ElementSize.Word or ElementSize.DoubleWord. Note - * ElementSize.DoubleWord is only applicable when size is 128 (i.e. the operation is - * performed on more than one element). + * @param eSize element size. ElementSize.DoubleWord is only applicable when size is 128 (i.e. + * the operation is performed on more than one element). * @param dst SIMD register. * @param src SIMD register. * @param shiftAmt shift right amount. diff --git a/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Address.java b/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Address.java index f7cd220d04df..da9733e7ee79 100644 --- a/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Address.java +++ b/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Address.java @@ -315,6 +315,15 @@ public static AArch64Address createPCLiteralAddress(int bitMemoryTransferSize) { return new AArch64Address(bitMemoryTransferSize, zr, zr, 0, false, null, AddressingMode.PC_LITERAL); } + /** + * @param bitMemoryTransferSize Memory operation size. + * @param base May not be null or the zero register. + * @return an address specifying the address pointed to by base. + */ + public static AArch64Address createPairBaseRegisterOnlyAddress(int bitMemoryTransferSize, Register base) { + return createImmediateAddress(bitMemoryTransferSize, AddressingMode.IMMEDIATE_PAIR_SIGNED_SCALED, base, 0); + } + /** * AArch64Address specifying a structure memory access of the form "[Xn|SP]". */ diff --git a/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java b/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java index 479122cbc938..941e23cd4767 100755 --- a/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java +++ b/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java @@ -991,48 +991,46 @@ private static int getConditionalBranchImm(int imm21) { } /* Unconditional Branch (immediate) (5.2.2) */ + protected void b() { + unconditionalBranchImmInstruction(0, Instruction.B, -1, true); + } /** + * Unconditional Branch (immediate) (5.2.2). + * * @param imm28 Signed 28-bit offset, has to be word aligned. */ protected void b(int imm28) { - unconditionalBranchImmInstruction(imm28, Instruction.B, -1); + unconditionalBranchImmInstruction(imm28, Instruction.B, -1, false); } /** + * Unconditional Branch (immediate) (5.2.2). * * @param imm28 Signed 28-bit offset, has to be word aligned. * @param pos Position where instruction is inserted into code buffer. */ protected void b(int imm28, int pos) { - unconditionalBranchImmInstruction(imm28, Instruction.B, pos); + unconditionalBranchImmInstruction(imm28, Instruction.B, pos, false); } /** * Branch and link return address to register X30. - * - * @param imm28 Signed 28-bit offset, has to be word aligned. */ - public void bl(int imm28) { - /* - * Currently within Graal all bl instructions will be patched later. - * - * Hence, for now imm28 should always be 0. If at a later time the imm28 can be a meaningful - * value, then this assert can be reevaluated. - */ - assert imm28 == 0; - unconditionalBranchImmInstruction(imm28, Instruction.BL, -1); + public void bl() { + unconditionalBranchImmInstruction(0, Instruction.BL, -1, true); } - private void unconditionalBranchImmInstruction(int imm28, Instruction instr, int pos) { + private void unconditionalBranchImmInstruction(int imm28, Instruction instr, int pos, boolean needsImmAnnotation) { assert NumUtil.isSignedNbit(28, imm28) && (imm28 & 0x3) == 0 : "Immediate has to be 28bit signed number and word aligned"; int imm = (imm28 & NumUtil.getNbitNumberInt(28)) >> 2; int instrEncoding = instr.encoding | UnconditionalBranchImmOp; + if (needsImmAnnotation) { + annotatePatchingImmediate(pos == -1 ? position() : pos, instr, 26, 0, 2); + } if (pos == -1) { - annotatePatchingImmediate(position(), instr, 26, 0, 2); emitInt(instrEncoding | imm); } else { - annotatePatchingImmediate(pos, instr, 26, 0, 2); emitInt(instrEncoding | imm, pos); } } @@ -1077,7 +1075,7 @@ private void unconditionalBranchRegInstruction(Instruction instr, Register reg) /** * Returns the log2 size of the number of bytes expected to be transferred. */ - protected static int getLog2TransferSize(int bitMemoryTransferSize) { + public static int getLog2TransferSize(int bitMemoryTransferSize) { switch (bitMemoryTransferSize) { case 8: return 0; @@ -1267,11 +1265,9 @@ private void loadStoreInstruction(Instruction instr, Register reg, AArch64Addres int memOp = extraEncoding | transferSizeEncoding | instr.encoding | floatFlag | rt(reg); switch (address.getAddressingMode()) { case IMMEDIATE_UNSIGNED_SCALED: - annotatePatchingImmediate(position(), instr, 12, LoadStoreScaledImmOffset, log2TransferSize); emitInt(memOp | LoadStoreScaledOp | address.getImmediate() << LoadStoreScaledImmOffset | rs1(address.getBase())); break; case IMMEDIATE_SIGNED_UNSCALED: - annotatePatchingImmediate(position(), instr, 9, LoadStoreUnscaledImmOffset, 0); emitInt(memOp | LoadStoreUnscaledOp | address.getImmediate() << LoadStoreUnscaledImmOffset | rs1(address.getBase())); break; case BASE_REGISTER_ONLY: @@ -1289,11 +1285,9 @@ private void loadStoreInstruction(Instruction instr, Register reg, AArch64Addres emitInt(transferSizeEncoding | floatFlag | LoadLiteralOp | rd(reg) | address.getImmediate() << LoadLiteralImmOffset); break; case IMMEDIATE_POST_INDEXED: - annotatePatchingImmediate(position(), instr, 9, LoadStoreIndexedImmOffset, 0); emitInt(memOp | LoadStorePostIndexedOp | rs1(address.getBase()) | address.getImmediate() << LoadStoreIndexedImmOffset); break; case IMMEDIATE_PRE_INDEXED: - annotatePatchingImmediate(position(), instr, 9, LoadStoreIndexedImmOffset, 0); emitInt(memOp | LoadStorePreIndexedOp | rs1(address.getBase()) | address.getImmediate() << LoadStoreIndexedImmOffset); break; default: @@ -3121,7 +3115,14 @@ public abstract static class PatchableCodeAnnotation extends CodeAnnotation { this.instructionPosition = instructionPosition; } - abstract void patch(int codePos, int relative, byte[] code); + /** + * Patch the code buffer. + * + * @param startAddress starting address for instruction sequence to patch + * @param relative pc-relative value + * @param code machine code generated for this method + */ + abstract void patch(long startAddress, int relative, byte[] code); } /** @@ -3275,9 +3276,9 @@ public String toString() { } @Override - public void patch(int codePos, int relative, byte[] code) { - // currently only BL instructions are being patched here - assert instruction == Instruction.BL : "trying to patch an unexpected instruction"; + public void patch(long startAddress, int relative, byte[] code) { + // currently, only BL instructions are being patched here + GraalError.guarantee(instruction == Instruction.BL, "trying to patch an unexpected instruction"); int curValue = relative; // BL is PC-relative assert (curValue & ((1 << shift) - 1)) == 0 : "relative offset has incorrect alignment"; diff --git a/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java b/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java index 82e56e994a80..12fe044278f2 100755 --- a/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java +++ b/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java @@ -965,7 +965,7 @@ public void add(int size, Register dst, Register src1, Register src2, ShiftType } /** - * dst = src1 + shiftType(src2, shiftAmt & (size-1)) and sets condition flags. + * dst = src1 - shiftType(src2, shiftAmt & (size-1)) and sets condition flags. * * @param size register size. Has to be 32 or 64. * @param dst general purpose register. May not be null or stackpointer. @@ -986,7 +986,7 @@ public void sub(int size, Register dst, Register src1, Register src2, ShiftType } /** - * dst = -src1. + * dst = -src. * * @param size register size. Has to be 32 or 64. * @param dst general purpose register. May not be null or stackpointer. @@ -996,6 +996,19 @@ public void neg(int size, Register dst, Register src) { sub(size, dst, zr, src); } + /** + * dst = -(shiftType(src, shiftAmt & (size - 1))). + * + * @param size register size. Has to be 32 or 64. + * @param dst general purpose register. May not be null or stackpointer. + * @param src general purpose register. May not be null or stackpointer. + * @param shiftType right or left shift, arithmetic or logical. + * @param shiftAmt number of shift bits. Has to be between 0 and (size - 1). + */ + public void neg(int size, Register dst, Register src, ShiftType shiftType, int shiftAmt) { + sub(size, dst, zr, src, shiftType, shiftAmt); + } + /** * dst = src + immediate. * @@ -1781,7 +1794,7 @@ public void branchConditionally(ConditionFlag condition, Label label) { } /** - * Branches if condition is true. Address of jump is patched up by HotSpot c++ code. + * Branches if condition is true. Address of jump is patched up by the runtime. * * @param condition any condition value allowed. Non null. */ @@ -1820,11 +1833,10 @@ public void jmp(Register dest) { } /** - * Immediate jump instruction fixed up by HotSpot c++ code. + * Immediate jump instruction fixed up by the runtime. */ public void jmp() { - // Offset has to be fixed up by c++ code. - super.b(0); + super.b(); } /** @@ -2057,16 +2069,15 @@ public String toString() { } @Override - public void patch(int codePos, int relative, byte[] code) { - int pos = instructionPosition; - long targetAddress = ((long) pos) + relative; - int relativePageDifference = PatcherUtil.computeRelativePageDifference(targetAddress, pos, 1 << 12); - int originalInst = PatcherUtil.readInstruction(code, pos); + public void patch(long startAddress, int relative, byte[] code) { + long targetAddress = startAddress + relative; + int relativePageDifference = PatcherUtil.computeRelativePageDifference(targetAddress, startAddress, 1 << 12); + int originalInst = PatcherUtil.readInstruction(code, instructionPosition); int newInst = PatcherUtil.patchAdrpHi21(originalInst, relativePageDifference & 0x1FFFFF); - PatcherUtil.writeInstruction(code, pos, newInst); - originalInst = PatcherUtil.readInstruction(code, pos + 4); + PatcherUtil.writeInstruction(code, instructionPosition, newInst); + originalInst = PatcherUtil.readInstruction(code, instructionPosition + 4); newInst = PatcherUtil.patchLdrLo12(originalInst, (int) targetAddress & 0xFFF, srcSize); - PatcherUtil.writeInstruction(code, pos + 4, newInst); + PatcherUtil.writeInstruction(code, instructionPosition + 4, newInst); } } @@ -2081,16 +2092,15 @@ public String toString() { } @Override - public void patch(int codePos, int relative, byte[] code) { - int pos = instructionPosition; - long targetAddress = ((long) pos) + relative; - int relativePageDifference = PatcherUtil.computeRelativePageDifference(targetAddress, pos, 1 << 12); - int originalInst = PatcherUtil.readInstruction(code, pos); + public void patch(long startAddress, int relative, byte[] code) { + long targetAddress = startAddress + relative; + int relativePageDifference = PatcherUtil.computeRelativePageDifference(targetAddress, startAddress, 1 << 12); + int originalInst = PatcherUtil.readInstruction(code, instructionPosition); int newInst = PatcherUtil.patchAdrpHi21(originalInst, relativePageDifference & 0x1FFFFF); - PatcherUtil.writeInstruction(code, pos, newInst); - originalInst = PatcherUtil.readInstruction(code, pos + 4); + PatcherUtil.writeInstruction(code, instructionPosition, newInst); + originalInst = PatcherUtil.readInstruction(code, instructionPosition + 4); newInst = PatcherUtil.patchAddLo12(originalInst, (int) targetAddress & 0xFFF); - PatcherUtil.writeInstruction(code, pos + 4, newInst); + PatcherUtil.writeInstruction(code, instructionPosition + 4, newInst); } } @@ -2128,13 +2138,13 @@ public String toString() { } @Override - public void patch(int codePos, int relative, byte[] code) { + public void patch(long startAddress, int relative, byte[] code) { /* * Each move has a 16 bit immediate operand. We use a series of shifted moves to * represent immediate values larger than 16 bits. */ // first retrieving the target address - long curValue = ((long) instructionPosition) + relative; + long curValue = startAddress + relative; int siteOffset = 0; boolean containsNegatedMov = false; for (MovAction include : includeSet) { diff --git a/compiler/src/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java b/compiler/src/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java index e0eb84891213..51428351a555 100644 --- a/compiler/src/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java +++ b/compiler/src/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java @@ -1396,6 +1396,22 @@ public void emit(AMD64Assembler asm, AVXSize size, Register dst, AMD64Address sr asm.emitOperandHelper(dst, src, 1, getDisp8Scale(useEvex, size)); asm.emitByte(imm8); } + + public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src, int imm8, Register mask, int z, int b) { + assert assertion.check((AMD64) asm.target.arch, size, dst, null, src); + asm.evexPrefix(dst, mask, Register.None, src, size, pp, mmmmm, wEvex, z, b); + asm.emitByte(op); + asm.emitModRM(dst, src); + asm.emitByte(imm8); + } + + public void emit(AMD64Assembler asm, AVXSize size, Register dst, AMD64Address src, int imm8, Register mask, int z, int b) { + assert assertion.check((AMD64) asm.target.arch, size, dst, null, null); + asm.evexPrefix(dst, mask, Register.None, src, size, pp, mmmmm, wEvex, z, b); + asm.emitByte(op); + asm.emitOperandHelper(dst, src, 1, getDisp8Scale(true, size)); + asm.emitByte(imm8); + } } /** @@ -1598,6 +1614,7 @@ public static class VexRVMOp extends VexOp { public static final VexRVMOp VPBLENDMQ = new VexRVMOp("VPBLENDMQ", P_66, M_0F38, W1, 0x64, VEXOpAssertion.AVX512F_VL, EVEXTuple.FVM, W1); public static final VexRVMOp VBLENDMPS = new VexRVMOp("VBLENDMPS", P_66, M_0F38, W0, 0x65, VEXOpAssertion.AVX512F_VL, EVEXTuple.FVM, W0); public static final VexRVMOp VBLENDMPD = new VexRVMOp("VBLENDMPD", P_66, M_0F38, W1, 0x65, VEXOpAssertion.AVX512F_VL, EVEXTuple.FVM, W1); + public static final VexRVMOp VPERMT2B = new VexRVMOp("VPERMT2B", P_66, M_0F38, W0, 0x7D, VEXOpAssertion.AVX512F_VL, EVEXTuple.FVM, W0); // @formatter:on protected VexRVMOp(String opcode, int pp, int mmmmm, int w, int op, VEXOpAssertion assertion) { @@ -1636,6 +1653,20 @@ public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src1, asm.emitOperandHelper(dst, src2, 0, getDisp8Scale(useEvex, size)); } + public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src1, Register src2, Register mask, int z, int b) { + assert assertion.check((AMD64) asm.target.arch, size, dst, src1, src2); + asm.vexPrefix(dst, src1, src2, mask, size, pp, mmmmm, w, wEvex, false, assertion.l128feature, assertion.l256feature, z, b); + asm.emitByte(op); + asm.emitModRM(dst, src2); + } + + public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src1, AMD64Address src2, Register mask, int z, int b) { + assert assertion.check((AMD64) asm.target.arch, size, dst, src1, null); + boolean useEvex = asm.vexPrefix(dst, src1, src2, mask, size, pp, mmmmm, w, wEvex, false, assertion.l128feature, assertion.l256feature, z, b); + asm.emitByte(op); + asm.emitOperandHelper(dst, src2, 0, getDisp8Scale(useEvex, size)); + } + public boolean isPacked() { return pp == P_ || pp == P_66; } @@ -1662,6 +1693,7 @@ public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src1, asm.emitModRM(dst, src2); } + @Override public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src1, Register src2, Register mask, int z, int b) { assert assertion.check((AMD64) asm.target.arch, LZ, dst, src1, src2, null); assert size == AVXSize.DWORD || size == AVXSize.QWORD; @@ -1679,6 +1711,7 @@ public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src1, asm.emitOperandHelper(dst, src2, 0); } + @Override public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src1, AMD64Address src2, Register mask, int z, int b) { assert assertion.check((AMD64) asm.target.arch, LZ, dst, src1, null, null); assert size == AVXSize.DWORD || size == AVXSize.QWORD; diff --git a/compiler/src/org.graalvm.compiler.asm.test/src/org/graalvm/compiler/asm/test/AssemblerTest.java b/compiler/src/org.graalvm.compiler.asm.test/src/org/graalvm/compiler/asm/test/AssemblerTest.java index 6f464c509e3d..ea4162c958b4 100644 --- a/compiler/src/org.graalvm.compiler.asm.test/src/org/graalvm/compiler/asm/test/AssemblerTest.java +++ b/compiler/src/org.graalvm.compiler.asm.test/src/org/graalvm/compiler/asm/test/AssemblerTest.java @@ -104,10 +104,12 @@ protected InstalledCode assembleMethod(Method m, CodeGenTest test) { InstalledCode code = backend.addInstalledCode(debug, method, asCompilationRequest(compilationId), compResult); for (DisassemblerProvider dis : GraalServices.load(DisassemblerProvider.class)) { - String disasm1 = dis.disassembleCompiledCode(options, codeCache, compResult); - Assert.assertTrue(compResult.toString(), disasm1 == null || disasm1.length() > 0); - String disasm2 = dis.disassembleInstalledCode(codeCache, compResult, code); - Assert.assertTrue(code.toString(), disasm2 == null || disasm2.length() > 0); + if (dis.isAvailable(options)) { + String disasm1 = dis.disassembleCompiledCode(options, codeCache, compResult); + Assert.assertTrue(compResult.toString(), disasm1 == null || disasm1.length() > 0); + String disasm2 = dis.disassembleInstalledCode(codeCache, compResult, code); + Assert.assertTrue(code.toString(), disasm2 == null || disasm2.length() > 0); + } } return code; } catch (Throwable e) { diff --git a/compiler/src/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java b/compiler/src/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java index 81dcedc60999..b9c5ae56bb69 100644 --- a/compiler/src/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java +++ b/compiler/src/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java @@ -37,7 +37,6 @@ import java.util.function.Function; import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.graph.NodeSourcePosition; @@ -58,7 +57,6 @@ import jdk.vm.ci.code.site.Site; import jdk.vm.ci.meta.Assumptions.Assumption; import jdk.vm.ci.meta.InvokeTarget; -import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.SpeculationLog; @@ -137,7 +135,7 @@ public String toString() { /** * Describes a table of signed offsets embedded in the code. The offsets are relative to the - * starting address of the table. This type of table maybe generated when translating a + * starting address of the table. This type of table can be generated when translating a * multi-way branch based on a key value from a dense value set (e.g. the {@code tableswitch} * JVM instruction). * @@ -146,6 +144,31 @@ public String toString() { */ public static final class JumpTable extends CodeAnnotation { + /** + * Constants denoting the format and size of each entry in a jump table. + */ + public enum EntryFormat { + /** + * Each entry is a 4 byte offset. The base of the offset is platform dependent. + */ + OFFSET(4), + + /** + * Each entry is a secondary key value followed by a 4 byte offset. The base of the + * offset is platform dependent. + */ + KEY2_OFFSET(8); + + EntryFormat(int size) { + this.size = size; + } + + /** + * Gets the size of an entry in bytes. + */ + public final int size; + } + /** * The low value in the key range (inclusive). */ @@ -159,13 +182,16 @@ public static final class JumpTable extends CodeAnnotation { /** * The size (in bytes) of each table entry. */ - public final int entrySize; + public final EntryFormat entryFormat; - public JumpTable(int position, int low, int high, int entrySize) { + public JumpTable(int position, int low, int high, EntryFormat entryFormat) { super(position); + if (high <= low) { + throw new IllegalArgumentException(String.format("low (%d) is not less than high(%d)", low, high)); + } this.low = low; this.high = high; - this.entrySize = entrySize; + this.entryFormat = entryFormat; } @Override @@ -175,7 +201,7 @@ public boolean equals(Object obj) { } if (obj instanceof JumpTable) { JumpTable that = (JumpTable) obj; - if (this.getPosition() == that.getPosition() && this.entrySize == that.entrySize && this.low == that.low && this.high == that.high) { + if (this.getPosition() == that.getPosition() && this.entryFormat == that.entryFormat && this.low == that.low && this.high == that.high) { return true; } } @@ -239,33 +265,17 @@ public String toString() { */ private SpeculationLog speculationLog; - /** - * The list of fields that were accessed from the bytecodes. - */ - private ResolvedJavaField[] fields; - private int bytecodeSize; private boolean hasUnsafeAccess; - private boolean isImmutablePIC; - public CompilationResult(CompilationIdentifier compilationId) { - this(compilationId, null, false); + this(compilationId, null); } public CompilationResult(CompilationIdentifier compilationId, String name) { - this(compilationId, name, false); - } - - public CompilationResult(CompilationIdentifier compilationId, boolean isImmutablePIC) { - this(compilationId, null, isImmutablePIC); - } - - public CompilationResult(CompilationIdentifier compilationId, String name, boolean isImmutablePIC) { this.compilationId = compilationId; this.name = name; - this.isImmutablePIC = isImmutablePIC; } public CompilationResult(String name) { @@ -406,31 +416,6 @@ public SpeculationLog getSpeculationLog() { return speculationLog; } - /** - * Sets the fields that were referenced from the bytecodes that were used as input to the - * compilation. - * - * @param accessedFields the collected set of fields accessed during compilation - */ - public void setFields(EconomicSet accessedFields) { - if (accessedFields != null) { - fields = accessedFields.toArray(new ResolvedJavaField[accessedFields.size()]); - } - } - - /** - * Gets the fields that were referenced from bytecodes that were used as input to the - * compilation. - * - * The caller must not modify the contents of the returned array. - * - * @return {@code null} if the compilation did not record fields dependencies otherwise the - * fields that were accessed from bytecodes were used as input to the compilation. - */ - public ResolvedJavaField[] getFields() { - return fields; - } - public void setBytecodeSize(int bytecodeSize) { checkOpen(); this.bytecodeSize = bytecodeSize; @@ -475,10 +460,6 @@ public void setMaxInterpreterFrameSize(int maxInterpreterFrameSize) { this.maxInterpreterFrameSize = maxInterpreterFrameSize; } - public boolean isImmutablePIC() { - return this.isImmutablePIC; - } - /** * Sets the machine that has been generated by the compiler. * diff --git a/compiler/src/org.graalvm.compiler.code/src/org/graalvm/compiler/code/HexCodeFile.java b/compiler/src/org.graalvm.compiler.code/src/org/graalvm/compiler/code/HexCodeFile.java index 0e11d7796eff..e987d4bca74f 100644 --- a/compiler/src/org.graalvm.compiler.code/src/org/graalvm/compiler/code/HexCodeFile.java +++ b/compiler/src/org.graalvm.compiler.code/src/org/graalvm/compiler/code/HexCodeFile.java @@ -24,6 +24,9 @@ */ package org.graalvm.compiler.code; +import static org.graalvm.compiler.code.CompilationResult.JumpTable.EntryFormat.KEY2_OFFSET; +import static org.graalvm.compiler.code.CompilationResult.JumpTable.EntryFormat.OFFSET; + import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.io.PrintStream; @@ -37,8 +40,7 @@ import org.graalvm.compiler.code.CompilationResult.CodeAnnotation; import org.graalvm.compiler.code.CompilationResult.CodeComment; import org.graalvm.compiler.code.CompilationResult.JumpTable; - -import jdk.vm.ci.code.CodeUtil; +import org.graalvm.compiler.code.CompilationResult.JumpTable.EntryFormat; /** * A HexCodeFile is a textual format for representing a chunk of machine code along with extra @@ -59,7 +61,9 @@ * * OperandComment ::= "OperandComment" Position String * - * JumpTable ::= "JumpTable" Position EntrySize Low High + * EntryFormat ::= 4 | 8 | "OFFSET" | "KEY2_OFFSET" + * + * JumpTable ::= "JumpTable" Position EntryFormat Low High * * LookupTable ::= "LookupTable" Position NPairs KeySize OffsetSize * @@ -95,13 +99,13 @@ */ public class HexCodeFile { - public static final String NEW_LINE = CodeUtil.NEW_LINE; + public static final String NEW_LINE = System.lineSeparator(); public static final String SECTION_DELIM = " <||@"; public static final String COLUMN_END = " <|@"; public static final Pattern SECTION = Pattern.compile("(\\S+)\\s+(.*)", Pattern.DOTALL); public static final Pattern COMMENT = Pattern.compile("(\\d+)\\s+(.*)", Pattern.DOTALL); public static final Pattern OPERAND_COMMENT = COMMENT; - public static final Pattern JUMP_TABLE = Pattern.compile("(\\d+)\\s+(\\d+)\\s+(-{0,1}\\d+)\\s+(-{0,1}\\d+)\\s*"); + public static final Pattern JUMP_TABLE = Pattern.compile("(\\d+)\\s+(\\S+)\\s+(-{0,1}\\d+)\\s+(-{0,1}\\d+)\\s*"); public static final Pattern LOOKUP_TABLE = Pattern.compile("(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s*"); public static final Pattern HEX_CODE = Pattern.compile("(\\p{XDigit}+)(?:\\s+(\\p{XDigit}*))?"); public static final Pattern PLATFORM = Pattern.compile("(\\S+)\\s+(\\S+)", Pattern.DOTALL); @@ -173,7 +177,10 @@ public void writeTo(OutputStream out) { ps.printf("HexCode %x %s %s%n", startAddress, HexCodeFile.hexCodeString(code), SECTION_DELIM); for (JumpTable table : jumpTables) { - ps.printf("JumpTable %d %d %d %d %s%n", table.getPosition(), table.entrySize, table.low, table.high, SECTION_DELIM); + EntryFormat ef = table.entryFormat; + // Backwards compatibility support for old versions of C1Visualizer + String efString = ef == OFFSET || ef == KEY2_OFFSET ? String.valueOf(ef.size) : ef.name(); + ps.printf("JumpTable %d %s %d %d %s%n", table.getPosition(), efString, table.low, table.high, SECTION_DELIM); } for (Map.Entry> e : comments.entrySet()) { @@ -433,13 +440,30 @@ void parseSection(int offset, String section) { m = HexCodeFile.JUMP_TABLE.matcher(body); check(m.matches(), bodyOffset, "JumpTable does not match pattern " + HexCodeFile.JUMP_TABLE); int pos = parseInt(bodyOffset + m.start(1), m.group(1)); - int entrySize = parseInt(bodyOffset + m.start(2), m.group(2)); + JumpTable.EntryFormat entryFormat = parseJumpTableEntryFormat(m, bodyOffset); int low = parseInt(bodyOffset + m.start(3), m.group(3)); int high = parseInt(bodyOffset + m.start(4), m.group(4)); - hcf.jumpTables.add(new JumpTable(pos, low, high, entrySize)); + hcf.jumpTables.add(new JumpTable(pos, low, high, entryFormat)); } else { error(offset, "Unknown section header: " + header); } } + + private JumpTable.EntryFormat parseJumpTableEntryFormat(Matcher m, int bodyOffset) throws Error { + String entryFormatName = m.group(2); + JumpTable.EntryFormat entryFormat; + if ("4".equals(entryFormatName)) { + entryFormat = EntryFormat.OFFSET; + } else if ("8".equals(entryFormatName)) { + entryFormat = EntryFormat.KEY2_OFFSET; + } else { + try { + entryFormat = EntryFormat.valueOf(entryFormatName); + } catch (IllegalArgumentException e) { + throw error(bodyOffset + m.start(2), "Not a valid " + EntryFormat.class.getSimpleName() + " value: " + entryFormatName); + } + } + return entryFormat; + } } } diff --git a/compiler/src/org.graalvm.compiler.code/src/org/graalvm/compiler/code/HexCodeFileDisassemblerProvider.java b/compiler/src/org.graalvm.compiler.code/src/org/graalvm/compiler/code/HexCodeFileDisassemblerProvider.java index 409438ff72ae..eac63bd2e3ef 100644 --- a/compiler/src/org.graalvm.compiler.code/src/org/graalvm/compiler/code/HexCodeFileDisassemblerProvider.java +++ b/compiler/src/org.graalvm.compiler.code/src/org/graalvm/compiler/code/HexCodeFileDisassemblerProvider.java @@ -26,6 +26,7 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.reflect.Method; import java.util.Arrays; import org.graalvm.compiler.options.OptionValues; @@ -43,6 +44,7 @@ import jdk.vm.ci.code.site.DataPatch; import jdk.vm.ci.code.site.ExceptionHandler; import jdk.vm.ci.code.site.Infopoint; +import jdk.vm.ci.services.Services; /** * {@link HexCodeFile} based implementation of {@link DisassemblerProvider}. @@ -124,6 +126,11 @@ private static void addOperandComment(HexCodeFile hcf, int pos, String comment) hcf.addOperandComment(pos, comment); } + @Override + public boolean isAvailable(OptionValues options) { + return HexCodeFileDisTool.processMethod != null; + } + /** * Interface to the tool for disassembling an {@link HexCodeFile#toEmbeddedString() embedded} * {@link HexCodeFile}. @@ -135,10 +142,31 @@ static class HexCodeFileDisTool { MethodHandle toolMethod = null; try { Class toolClass = Class.forName("com.oracle.max.hcfdis.HexCodeFileDis", true, ClassLoader.getSystemClassLoader()); - toolMethod = MethodHandles.lookup().unreflect(toolClass.getDeclaredMethod("processEmbeddedString", String.class)); + Method reflectMethod = toolClass.getDeclaredMethod("processEmbeddedString", String.class); + reflectMethod.setAccessible(true); + toolMethod = MethodHandles.lookup().unreflect(reflectMethod); } catch (Exception e) { // Tool not available on the class path } + + // Try disassemble a zero-length code array to see if the disassembler + // can really be used (e.g., the Capstone native support may be not available on the + // current platform). + if (toolMethod != null) { + byte[] code = {}; + String arch = Services.getSavedProperties().get("os.arch"); + if (arch.equals("x86_64")) { + arch = "amd64"; + } + int wordWidth = arch.endsWith("64") ? 64 : Integer.parseInt(Services.getSavedProperties().getOrDefault("sun.arch.data.model", "64")); + String hcf = new HexCodeFile(code, 0L, arch.toLowerCase(), wordWidth).toEmbeddedString(); + try { + toolMethod.invokeExact(hcf); + } catch (Throwable e) { + toolMethod = null; + } + } + processMethod = toolMethod; } diff --git a/compiler/src/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64BitFieldTest.java b/compiler/src/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64BitFieldTest.java index 7212af4f80fd..18ed28f5b4bd 100644 --- a/compiler/src/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64BitFieldTest.java +++ b/compiler/src/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64BitFieldTest.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019, 2020, Arm Limited and affiliates. All rights reserved. + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2021, Arm Limited and affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -207,7 +207,7 @@ public void testSignedI2LInsert() { // SBFIZ with B2I. public int signedB2IInsert(int input) { byte b = (byte) input; - return b << 31; + return b << 30; } @Test diff --git a/compiler/src/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64NegateShiftTest.java b/compiler/src/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64NegateShiftTest.java new file mode 100644 index 000000000000..6917c7f868cd --- /dev/null +++ b/compiler/src/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64NegateShiftTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Arm Limited and affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.core.aarch64.test; + +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp; +import org.junit.Test; + +import java.util.function.Predicate; + +public class AArch64NegateShiftTest extends AArch64MatchRuleTest { + private static final Predicate predicate = op -> (op instanceof AArch64ArithmeticOp.BinaryShiftOp); + + /** + * negateShift match rule tests for shift operations with int type. + */ + public int negShiftLeftLogicInt(int input) { + return -(input << 5); + } + + @Test + public void testNegShiftLeftLogicInt() { + test("negShiftLeftLogicInt", 123); + checkLIR("negShiftLeftLogicInt", predicate, 1); + } + + public int negShiftRightLogicInt(int input) { + return -(input >>> 6); + } + + @Test + public void testNegShiftRightLogicInt() { + test("negShiftRightLogicInt", 123); + checkLIR("negShiftRightLogicInt", predicate, 1); + } + + public int negShiftRightArithInt(int input) { + return -(input >> 7); + } + + @Test + public void testNegShiftRightArithInt() { + test("negShiftRightArithInt", 123); + checkLIR("negShiftRightArithInt", predicate, 1); + } + + /** + * negateShift match rule tests for shift operations with long type. + */ + public long negShiftLeftLogicLong(long input) { + return -(input << 8); + } + + @Test + public void testNegShiftLeftLogicLong() { + test("negShiftLeftLogicLong", 123L); + checkLIR("negShiftLeftLogicLong", predicate, 1); + } + + public long negShiftRightLogicLong(long input) { + return -(input >>> 9); + } + + @Test + public void testNegShiftRightLogicLong() { + test("negShiftRightLogicLong", 123L); + checkLIR("negShiftRightLogicLong", predicate, 1); + } + + public long negShiftRightArithLong(long input) { + return -(input >> 10); + } + + @Test + public void testNegShiftRightArithLong() { + test("negShiftRightArithLong", 123L); + checkLIR("negShiftRightArithLong", predicate, 1); + } +} diff --git a/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java b/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java index 4843f0724b70..a9f8c5d91238 100644 --- a/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java +++ b/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java @@ -56,7 +56,6 @@ import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreConstantOp; import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreOp; import org.graalvm.compiler.lir.aarch64.AArch64ReinterpretOp; -import org.graalvm.compiler.lir.aarch64.AArch64Unary; import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator; import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool; @@ -117,23 +116,16 @@ protected Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlag } } - public Value emitExtendMemory(boolean isSigned, AArch64Kind memoryKind, int resultBits, AArch64AddressValue address, LIRFrameState state) { - // Issue a zero extending load of the proper bit size and set the result to - // the proper kind. + public Value emitExtendMemory(boolean isSigned, AArch64Kind accessKind, int resultBits, AArch64AddressValue address, LIRFrameState state) { + /* + * Issue an extending load of the proper bit size and set the result to the proper kind. + */ + GraalError.guarantee(accessKind.isInteger(), "can only extend integer kinds"); Variable result = getLIRGen().newVariable(LIRKind.value(resultBits == 32 ? AArch64Kind.DWORD : AArch64Kind.QWORD)); - int targetSize = resultBits <= 32 ? 32 : 64; - switch (memoryKind) { - case BYTE: - case WORD: - case DWORD: - case QWORD: - getLIRGen().append(new AArch64Unary.MemoryOp(isSigned, targetSize, - memoryKind.getSizeInBytes() * Byte.SIZE, result, address, state)); - break; - default: - throw GraalError.shouldNotReachHere(); - } + int dstBitSize = resultBits <= 32 ? 32 : 64; + AArch64Move.ExtendKind extend = isSigned ? AArch64Move.ExtendKind.SIGN_EXTEND : AArch64Move.ExtendKind.ZERO_EXTEND; + getLIRGen().append(new AArch64Move.LoadOp(accessKind, dstBitSize, extend, result, address, state)); return result; } diff --git a/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64MoveFactory.java b/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64MoveFactory.java index 2fc3878e3145..11c042c55f27 100644 --- a/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64MoveFactory.java +++ b/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64MoveFactory.java @@ -39,6 +39,7 @@ import org.graalvm.compiler.lir.aarch64.AArch64Move.LoadAddressOp; import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory; +import jdk.vm.ci.aarch64.AArch64Kind; import jdk.vm.ci.meta.AllocatableValue; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; @@ -59,14 +60,14 @@ public LIRInstruction createMove(AllocatableValue dst, Value src) { if (srcIsSlot && dstIsSlot) { throw GraalError.shouldNotReachHere(src.getClass() + " " + dst.getClass()); } else { - return new AArch64Move.Move(dst, (AllocatableValue) src); + return new AArch64Move.Move((AArch64Kind) dst.getPlatformKind(), dst, (AllocatableValue) src); } } } @Override public LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input) { - return new AArch64Move.Move(result, input); + return new AArch64Move.Move((AArch64Kind) result.getPlatformKind(), result, input); } @Override diff --git a/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java b/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java index 4b5aab8615c5..16f56fe1cf52 100644 --- a/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java +++ b/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import org.graalvm.collections.EconomicMap; import org.graalvm.collections.Equivalence; +import org.graalvm.compiler.asm.aarch64.AArch64Assembler; import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ExtendType; import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; import org.graalvm.compiler.core.common.LIRKind; @@ -55,6 +56,7 @@ import org.graalvm.compiler.nodes.calc.AndNode; import org.graalvm.compiler.nodes.calc.BinaryNode; import org.graalvm.compiler.nodes.calc.FloatConvertNode; +import org.graalvm.compiler.nodes.calc.IntegerConvertNode; import org.graalvm.compiler.nodes.calc.IntegerLessThanNode; import org.graalvm.compiler.nodes.calc.LeftShiftNode; import org.graalvm.compiler.nodes.calc.MulNode; @@ -72,6 +74,7 @@ import org.graalvm.compiler.nodes.calc.ZeroExtendNode; import org.graalvm.compiler.nodes.memory.MemoryAccess; +import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.aarch64.AArch64Kind; import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.meta.AllocatableValue; @@ -152,6 +155,20 @@ protected AArch64Kind getMemoryKind(MemoryAccess access) { return (AArch64Kind) gen.getLIRKind(((ValueNode) access).stamp(NodeView.DEFAULT)).getPlatformKind(); } + private static boolean isSupportedExtendedAddSubShift(IntegerConvertNode node, int clampedShiftAmt) { + assert clampedShiftAmt >= 0; + if (clampedShiftAmt <= 4) { + switch (node.getInputBits()) { + case Byte.SIZE: + case Short.SIZE: + case Integer.SIZE: + case Long.SIZE: + return true; + } + } + return false; + } + private static ExtendType getZeroExtendType(int fromBits) { switch (fromBits) { case Byte.SIZE: @@ -300,7 +317,7 @@ private ComplexMatchResult emitExtendedAddSubShift(BinaryNode op, ValueNode x, V public ComplexMatchResult mergeSignExtendByShiftIntoAddSub(BinaryNode op, LeftShiftNode lshift, ValueNode ext, ValueNode x, ValueNode y) { assert isNumericInteger(lshift); int shiftAmt = getClampedShiftAmt(lshift); - if (shiftAmt > 4) { + if (!isSupportedExtendedAddSubShift((IntegerConvertNode) ext, shiftAmt)) { return null; } ExtendType extType; @@ -390,7 +407,7 @@ public ComplexMatchResult extendedPointerAddShift(AArch64PointerAddNode addP) { zeroExtend = (ZeroExtendNode) shift.getX(); shiftAmt = getClampedShiftAmt(shift); } - if (shiftAmt > 4) { + if (!isSupportedExtendedAddSubShift(zeroExtend, shiftAmt)) { return null; } @@ -667,6 +684,25 @@ public ComplexMatchResult logicShift(BinaryNode binary, ValueNode a, BinaryNode return emitBinaryShift(op, a, (ShiftNode) shift); } + /** + * Goal: fold shift into negate operation using AArch64's sub (shifted register) instruction. + */ + @MatchRule("(Negate (UnsignedRightShift=shift a Constant=b))") + @MatchRule("(Negate (RightShift=shift a Constant=b))") + @MatchRule("(Negate (LeftShift=shift a Constant=b))") + public ComplexMatchResult negShift(BinaryNode shift, ValueNode a, ConstantNode b) { + assert isNumericInteger(a, b); + int shiftAmt = getClampedShiftAmt((ShiftNode) shift); + AArch64Assembler.ShiftType shiftType = shiftTypeMap.get(shift.getClass()); + return builder -> { + AllocatableValue src = moveSp(gen.asAllocatable(operand(a))); + LIRKind kind = LIRKind.combine(operand(a)); + Variable result = gen.newVariable(kind); + gen.append(new AArch64ArithmeticOp.BinaryShiftOp(AArch64ArithmeticOp.SUB, result, AArch64.zr.asValue(kind), src, shiftType, shiftAmt)); + return result; + }; + } + /** * Goal: use AArch64's and not (bic) & or not (orn) instructions. */ @@ -849,6 +885,10 @@ public ComplexMatchResult mergeDowncastIntoAddSub(BinaryNode op, ValueNode x, Va @MatchRule("(Add=op x (ZeroExtend=ext y))") @MatchRule("(Sub=op x (ZeroExtend=ext y))") public ComplexMatchResult mergeSignExtendIntoAddSub(BinaryNode op, UnaryNode ext, ValueNode x, ValueNode y) { + if (!isSupportedExtendedAddSubShift((IntegerConvertNode) ext, 0)) { + return null; + } + ExtendType extType; if (ext instanceof SignExtendNode) { extType = getSignExtendType(((SignExtendNode) ext).getInputBits()); diff --git a/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64SuitesCreator.java b/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64SuitesCreator.java index f484cd6351d5..18aa11bb7e2a 100644 --- a/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64SuitesCreator.java +++ b/compiler/src/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64SuitesCreator.java @@ -30,23 +30,23 @@ import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.java.DefaultSuitesCreator; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.spi.CoreProviders; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.BasePhase; -import org.graalvm.compiler.phases.Phase; import org.graalvm.compiler.phases.PhaseSuite; import org.graalvm.compiler.phases.tiers.CompilerConfiguration; import org.graalvm.compiler.phases.tiers.LowTierContext; import org.graalvm.compiler.phases.tiers.Suites; public class AArch64SuitesCreator extends DefaultSuitesCreator { - private final List> insertReadReplacementBeforePositions; + private final List>> insertReadReplacementBeforePositions; - public AArch64SuitesCreator(CompilerConfiguration compilerConfiguration, Plugins plugins, List> insertReadReplacementBeforePositions) { + public AArch64SuitesCreator(CompilerConfiguration compilerConfiguration, Plugins plugins, List>> insertReadReplacementBeforePositions) { super(compilerConfiguration, plugins); this.insertReadReplacementBeforePositions = insertReadReplacementBeforePositions; } - public AArch64SuitesCreator(CompilerConfiguration compilerConfiguration, List> insertReadReplacementBeforePositions) { + public AArch64SuitesCreator(CompilerConfiguration compilerConfiguration, List>> insertReadReplacementBeforePositions) { super(compilerConfiguration); this.insertReadReplacementBeforePositions = insertReadReplacementBeforePositions; } @@ -55,7 +55,7 @@ public AArch64SuitesCreator(CompilerConfiguration compilerConfiguration, List> findPhase = null; - for (Class phase : insertReadReplacementBeforePositions) { + for (Class> phase : insertReadReplacementBeforePositions) { findPhase = suites.getLowTier().findPhase(phase); if (findPhase != null) { // Put AArch64ReadReplacementPhase right before the requested phase diff --git a/compiler/src/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java b/compiler/src/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java index 5989749c0d67..ad9af381ee30 100644 --- a/compiler/src/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java +++ b/compiler/src/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java @@ -79,7 +79,6 @@ import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.SD; import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.SS; import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.WORD; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.lir.LIRValueUtil.asConstantValue; import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; @@ -1370,7 +1369,7 @@ public void emitCompareOp(AMD64Kind cmpKind, Variable left, Value right) { return; } else if (c instanceof VMConstant) { VMConstant vc = (VMConstant) c; - if (size == DWORD && !GeneratePIC.getValue(getOptions()) && getLIRGen().target().inlineObjects) { + if (size == DWORD && getLIRGen().target().inlineObjects) { getLIRGen().append(new AMD64BinaryConsumer.VMConstOp(CMP.getMIOpcode(DWORD, false), left, vc)); } else { getLIRGen().append(new AMD64BinaryConsumer.DataOp(CMP.getRMOpcode(size), size, left, vc)); diff --git a/compiler/src/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java b/compiler/src/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java index 69fd3b4c9c02..baf0eb032138 100644 --- a/compiler/src/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java +++ b/compiler/src/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java @@ -33,7 +33,6 @@ import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.PD; import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.PS; import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.QWORD; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.lir.LIRValueUtil.asConstant; import static org.graalvm.compiler.lir.LIRValueUtil.asConstantValue; import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; @@ -349,7 +348,7 @@ private void emitRawCompareBranch(OperandSize size, Variable left, Value right, return; } else if (c instanceof VMConstant) { VMConstant vc = (VMConstant) c; - if (size == DWORD && !GeneratePIC.getValue(getResult().getLIR().getOptions()) && target().inlineObjects) { + if (size == DWORD && target().inlineObjects) { append(new CmpConstBranchOp(DWORD, left, vc, null, cond, trueLabel, falseLabel, trueLabelProbability)); } else { append(new CmpDataBranchOp(size, left, vc, cond, trueLabel, falseLabel, trueLabelProbability)); @@ -573,7 +572,7 @@ public void emitMembar(int barriers) { @Override protected void emitForeignCallOp(ForeignCallLinkage linkage, Value targetAddress, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { long maxOffset = linkage.getMaxCallTargetOffset(); - if (maxOffset != (int) maxOffset && !GeneratePIC.getValue(getResult().getLIR().getOptions())) { + if (maxOffset != (int) maxOffset) { append(new AMD64Call.DirectFarForeignCallOp(linkage, result, arguments, temps, info)); } else { append(new AMD64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info)); @@ -764,4 +763,16 @@ public void emitZeroMemory(Value address, Value length, boolean isAligned) { emitMove(lengthReg, length); append(new AMD64ZeroMemoryOp(asAddressValue(address), lengthReg)); } + + public boolean supportsCPUFeature(AMD64.CPUFeature feature) { + return ((AMD64) target().arch).getFeatures().contains(feature); + } + + public boolean supportsCPUFeature(String feature) { + try { + return ((AMD64) target().arch).getFeatures().contains(AMD64.CPUFeature.valueOf(feature)); + } catch (IllegalArgumentException e) { + return false; + } + } } diff --git a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java index 3f73efbfaa7d..02539c0d3c31 100644 --- a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java +++ b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java @@ -199,16 +199,6 @@ public final class GraalOptions { @Option(help = "", type = OptionType.Debug) public static final OptionKey CanOmitFrame = new OptionKey<>(true); - // Ahead of time compilation - @Option(help = "Try to avoid emitting code where patching is required", type = OptionType.Expert) - public static final OptionKey ImmutableCode = new OptionKey<>(false); - - @Option(help = "Generate position independent code", type = OptionType.Expert) - public static final OptionKey GeneratePIC = new OptionKey<>(false); - - @Option(help = "Generate verify oop checks in AOT code", type = OptionType.Expert) - public static final OptionKey AOTVerifyOops = new OptionKey<>(false); - // Runtime settings @Option(help = "", type = OptionType.Expert) public static final OptionKey SupportJsrBytecodes = new OptionKey<>(true); diff --git a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java index 80763dc56fb7..9dcc2cad9222 100644 --- a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java +++ b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java @@ -43,6 +43,7 @@ import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp; import org.graalvm.compiler.debug.GraalError; + import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; @@ -77,6 +78,8 @@ private IntegerStamp(int bits, long lowerBound, long upperBound, long downMask, assert upperBound <= CodeUtil.maxValue(bits) : this; assert (downMask & CodeUtil.mask(bits)) == downMask : this; assert (upMask & CodeUtil.mask(bits)) == upMask : this; + // Check for valid masks or the empty encoding + assert (downMask & ~upMask) == 0 || (upMask == 0 && downMask == CodeUtil.mask(bits)) : String.format("\u21ca: %016x \u21c8: %016x", downMask, upMask); } public static IntegerStamp create(int bits, long lowerBoundInput, long upperBoundInput) { @@ -132,7 +135,7 @@ private static long significantBit(long bits, long value) { private static long minValueForMasks(int bits, long downMask, long upMask) { if (significantBit(bits, upMask) == 0) { // Value is always positive. Minimum value always positive. - assert significantBit(bits, downMask) == 0; + assert significantBit(bits, downMask) == 0 : String.format("\u21ca: %016x \u21c8: %016x", downMask, upMask); return downMask; } else { // Value can be positive or negative. Minimum value always negative. @@ -152,6 +155,15 @@ private static long maxValueForMasks(int bits, long downMask, long upMask) { } public static IntegerStamp stampForMask(int bits, long downMask, long upMask) { + /* + * Determine if the new stamp created by down & upMask would be contradicting, i.e., empty + * by definition. This can happen for example if binary logic operations are evaluated + * repetitively on different branches creating values that are infeasible by definition + * (logic nodes on phi nodes of false evaluated predecessors). + */ + if ((downMask & ~upMask) != 0L) { + return createEmptyStamp(bits); + } return new IntegerStamp(bits, minValueForMasks(bits, downMask, upMask), maxValueForMasks(bits, downMask, upMask), downMask, upMask); } @@ -162,7 +174,11 @@ public IntegerStamp unrestricted() { @Override public IntegerStamp empty() { - return new IntegerStamp(getBits(), CodeUtil.maxValue(getBits()), CodeUtil.minValue(getBits()), CodeUtil.mask(getBits()), 0); + return createEmptyStamp(getBits()); + } + + private static IntegerStamp createEmptyStamp(int bits) { + return new IntegerStamp(bits, CodeUtil.maxValue(bits), CodeUtil.minValue(bits), CodeUtil.mask(bits), 0); } @Override @@ -1297,8 +1313,12 @@ public Constant getZero(Stamp s) { public Constant foldConstant(Constant value, int amount) { PrimitiveConstant c = (PrimitiveConstant) value; switch (c.getJavaKind()) { + case Byte: + return JavaConstant.forByte((byte) (c.asInt() << amount)); + case Char: + return JavaConstant.forChar((char) (c.asInt() << amount)); case Short: - return JavaConstant.forShort((short) (c.asLong() << amount)); + return JavaConstant.forShort((short) (c.asInt() << amount)); case Int: return JavaConstant.forInt(c.asInt() << amount); case Long: @@ -1365,9 +1385,7 @@ public Stamp foldStamp(Stamp stamp, IntegerStamp shift) { @Override public int getShiftAmountMask(Stamp s) { - IntegerStamp stamp = (IntegerStamp) s; - assert CodeUtil.isPowerOf2(stamp.getBits()); - return stamp.getBits() - 1; + return s.getStackKind().getBitCount() - 1; } }, @@ -1377,8 +1395,12 @@ public int getShiftAmountMask(Stamp s) { public Constant foldConstant(Constant value, int amount) { PrimitiveConstant c = (PrimitiveConstant) value; switch (c.getJavaKind()) { + case Byte: + return JavaConstant.forByte((byte) (c.asInt() >> amount)); + case Char: + return JavaConstant.forChar((char) (c.asInt() >> amount)); case Short: - return JavaConstant.forShort((short) (c.asLong() >> amount)); + return JavaConstant.forShort((short) (c.asInt() >> amount)); case Int: return JavaConstant.forInt(c.asInt() >> amount); case Long: @@ -1415,9 +1437,7 @@ public Stamp foldStamp(Stamp stamp, IntegerStamp shift) { @Override public int getShiftAmountMask(Stamp s) { - IntegerStamp stamp = (IntegerStamp) s; - assert CodeUtil.isPowerOf2(stamp.getBits()); - return stamp.getBits() - 1; + return s.getStackKind().getBitCount() - 1; } }, @@ -1427,6 +1447,12 @@ public int getShiftAmountMask(Stamp s) { public Constant foldConstant(Constant value, int amount) { PrimitiveConstant c = (PrimitiveConstant) value; switch (c.getJavaKind()) { + case Byte: + return JavaConstant.forByte((byte) (c.asInt() >>> amount)); + case Char: + return JavaConstant.forChar((char) (c.asInt() >>> amount)); + case Short: + return JavaConstant.forShort((short) (c.asInt() >>> amount)); case Int: return JavaConstant.forInt(c.asInt() >>> amount); case Long: @@ -1466,9 +1492,7 @@ public Stamp foldStamp(Stamp stamp, IntegerStamp shift) { @Override public int getShiftAmountMask(Stamp s) { - IntegerStamp stamp = (IntegerStamp) s; - assert CodeUtil.isPowerOf2(stamp.getBits()); - return stamp.getBits() - 1; + return s.getStackKind().getBitCount() - 1; } }, diff --git a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/PrimitiveStamp.java b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/PrimitiveStamp.java index f8f5385bb433..5d6567fcdc74 100644 --- a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/PrimitiveStamp.java +++ b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/PrimitiveStamp.java @@ -24,6 +24,8 @@ */ package org.graalvm.compiler.core.common.type; +import org.graalvm.compiler.debug.GraalError; + import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.MemoryAccessProvider; @@ -59,8 +61,18 @@ public static int getBits(Stamp stamp) { } } + private static boolean isAligned(long displacement, int numBits) { + GraalError.guarantee((numBits & 7) == 0, "numBits not a multiple of 8: %d", numBits); + int numBytes = numBits / 8; + return displacement % numBytes == 0; + } + @Override public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) { + if (!isAligned(displacement, getBits())) { + // Avoid crash when performing unaligned reads (JDK-8275645) + return null; + } try { return provider.readPrimitiveConstant(getStackKind(), base, displacement, getBits()); } catch (IllegalArgumentException e) { diff --git a/compiler/src/org.graalvm.compiler.core.jdk9.test/src/org/graalvm/compiler/core/jdk9/test/UnsafeGetStableArrayElement.java b/compiler/src/org.graalvm.compiler.core.jdk9.test/src/org/graalvm/compiler/core/jdk9/test/UnsafeGetStableArrayElement.java new file mode 100644 index 000000000000..c56b72001ebc --- /dev/null +++ b/compiler/src/org.graalvm.compiler.core.jdk9.test/src/org/graalvm/compiler/core/jdk9/test/UnsafeGetStableArrayElement.java @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.graalvm.compiler.core.jdk9.test; + +import static jdk.internal.misc.Unsafe.ARRAY_BOOLEAN_BASE_OFFSET; +import static jdk.internal.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET; +import static jdk.internal.misc.Unsafe.ARRAY_CHAR_BASE_OFFSET; +import static jdk.internal.misc.Unsafe.ARRAY_DOUBLE_BASE_OFFSET; +import static jdk.internal.misc.Unsafe.ARRAY_FLOAT_BASE_OFFSET; +import static jdk.internal.misc.Unsafe.ARRAY_INT_BASE_OFFSET; +import static jdk.internal.misc.Unsafe.ARRAY_LONG_BASE_OFFSET; +import static jdk.internal.misc.Unsafe.ARRAY_OBJECT_BASE_OFFSET; +import static jdk.internal.misc.Unsafe.ARRAY_SHORT_BASE_OFFSET; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.StructuredGraph.Builder; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.test.AddExports; +import org.junit.Assert; + +import jdk.internal.misc.Unsafe; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.InvalidInstalledCodeException; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * This is based on {@code test/hotspot/jtreg/compiler/unsafe/UnsafeGetStableArrayElement.java} and + * differs in that it only asserts the behavior of Graal with respect to reading an element from a + * {@code Stable} array via Unsafe. + */ +@AddExports("java.base/jdk.internal.misc") +public class UnsafeGetStableArrayElement extends GraalCompilerTest { + // @formatter:off + private static final List StableArrays = new ArrayList<>(); + private static T register(T t) { StableArrays.add(t); return t; } + + // These are treated as @Stable fields thanks to the applyStable method + static final boolean[] STABLE_BOOLEAN_ARRAY = register(new boolean[16]); + static final byte[] STABLE_BYTE_ARRAY = register(new byte[16]); + static final short[] STABLE_SHORT_ARRAY = register(new short[8]); + static final char[] STABLE_CHAR_ARRAY = register(new char[8]); + static final int[] STABLE_INT_ARRAY = register(new int[4]); + static final long[] STABLE_LONG_ARRAY = register(new long[2]); + static final float[] STABLE_FLOAT_ARRAY = register(new float[4]); + static final double[] STABLE_DOUBLE_ARRAY = register(new double[2]); + static final Object[] STABLE_OBJECT_ARRAY = register(new Object[4]); + + static { + Setter.reset(); + } + static final Unsafe U = Unsafe.getUnsafe(); + + static class Setter { + private static void setZ(boolean defaultVal) { STABLE_BOOLEAN_ARRAY[0] = defaultVal ? false : true; } + private static void setB(boolean defaultVal) { STABLE_BYTE_ARRAY[0] = defaultVal ? 0 : Byte.MAX_VALUE; } + private static void setS(boolean defaultVal) { STABLE_SHORT_ARRAY[0] = defaultVal ? 0 : Short.MAX_VALUE; } + private static void setC(boolean defaultVal) { STABLE_CHAR_ARRAY[0] = defaultVal ? 0 : Character.MAX_VALUE; } + private static void setI(boolean defaultVal) { STABLE_INT_ARRAY[0] = defaultVal ? 0 : Integer.MAX_VALUE; } + private static void setJ(boolean defaultVal) { STABLE_LONG_ARRAY[0] = defaultVal ? 0 : Long.MAX_VALUE; } + private static void setF(boolean defaultVal) { STABLE_FLOAT_ARRAY[0] = defaultVal ? 0 : Float.MAX_VALUE; } + private static void setD(boolean defaultVal) { STABLE_DOUBLE_ARRAY[0] = defaultVal ? 0 : Double.MAX_VALUE; } + private static void setL(boolean defaultVal) { STABLE_OBJECT_ARRAY[0] = defaultVal ? null : new Object(); } + + static void reset() { + setZ(false); + setB(false); + setS(false); + setC(false); + setI(false); + setJ(false); + setF(false); + setD(false); + setL(false); + } + } + + static class Test { + static void changeZ() { Setter.setZ(true); } + static void changeB() { Setter.setB(true); } + static void changeS() { Setter.setS(true); } + static void changeC() { Setter.setC(true); } + static void changeI() { Setter.setI(true); } + static void changeJ() { Setter.setJ(true); } + static void changeF() { Setter.setF(true); } + static void changeD() { Setter.setD(true); } + static void changeL() { Setter.setL(true); } + + static boolean testZ_Z() { return U.getBoolean(STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static byte testZ_B() { return U.getByte( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static short testZ_S() { return U.getShort( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static char testZ_C() { return U.getChar( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static int testZ_I() { return U.getInt( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static long testZ_J() { return U.getLong( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static float testZ_F() { return U.getFloat( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static double testZ_D() { return U.getDouble( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + + static boolean testB_Z() { return U.getBoolean(STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static byte testB_B() { return U.getByte( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static short testB_S() { return U.getShort( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static char testB_C() { return U.getChar( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static int testB_I() { return U.getInt( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static long testB_J() { return U.getLong( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static float testB_F() { return U.getFloat( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static double testB_D() { return U.getDouble( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + + static boolean testS_Z() { return U.getBoolean(STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static byte testS_B() { return U.getByte( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static short testS_S() { return U.getShort( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static char testS_C() { return U.getChar( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static int testS_I() { return U.getInt( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static long testS_J() { return U.getLong( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static float testS_F() { return U.getFloat( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static double testS_D() { return U.getDouble( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + + static boolean testC_Z() { return U.getBoolean(STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static byte testC_B() { return U.getByte( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static short testC_S() { return U.getShort( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static char testC_C() { return U.getChar( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static int testC_I() { return U.getInt( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static long testC_J() { return U.getLong( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static float testC_F() { return U.getFloat( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static double testC_D() { return U.getDouble( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + + static boolean testI_Z() { return U.getBoolean(STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static byte testI_B() { return U.getByte( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static short testI_S() { return U.getShort( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static char testI_C() { return U.getChar( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static int testI_I() { return U.getInt( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static long testI_J() { return U.getLong( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static float testI_F() { return U.getFloat( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static double testI_D() { return U.getDouble( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + + static boolean testJ_Z() { return U.getBoolean(STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static byte testJ_B() { return U.getByte( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static short testJ_S() { return U.getShort( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static char testJ_C() { return U.getChar( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static int testJ_I() { return U.getInt( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static long testJ_J() { return U.getLong( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static float testJ_F() { return U.getFloat( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static double testJ_D() { return U.getDouble( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + + static boolean testF_Z() { return U.getBoolean(STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static byte testF_B() { return U.getByte( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static short testF_S() { return U.getShort( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static char testF_C() { return U.getChar( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static int testF_I() { return U.getInt( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static long testF_J() { return U.getLong( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static float testF_F() { return U.getFloat( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static double testF_D() { return U.getDouble( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + + static boolean testD_Z() { return U.getBoolean(STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static byte testD_B() { return U.getByte( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static short testD_S() { return U.getShort( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static char testD_C() { return U.getChar( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static int testD_I() { return U.getInt( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static long testD_J() { return U.getLong( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static float testD_F() { return U.getFloat( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static double testD_D() { return U.getDouble( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + + @SuppressWarnings("removal") + static Object testL_L() { return U.getObject( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static boolean testL_Z() { return U.getBoolean(STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static byte testL_B() { return U.getByte( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static short testL_S() { return U.getShort( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static char testL_C() { return U.getChar( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static int testL_I() { return U.getInt( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static long testL_J() { return U.getLong( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static float testL_F() { return U.getFloat( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static double testL_D() { return U.getDouble( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + + static short testS_U() { return U.getShortUnaligned(STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET + 1); } + static char testC_U() { return U.getCharUnaligned( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET + 1); } + static int testI_U() { return U.getIntUnaligned( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET + 1); } + static long testJ_U() { return U.getLongUnaligned( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET + 1); } + } + // @formatter:on + + void run(Callable c) throws Exception { + run(c, null, null); + } + + @Override + protected StructuredGraph parse(Builder builder, PhaseSuite graphBuilderSuite) { + StructuredGraph graph = super.parse(builder, graphBuilderSuite); + applyStable(graph); + return graph; + } + + /** + * Finds each {@link ConstantNode} in {@code graph} that wraps one of the {@link #StableArrays} + * and replaces it with {@link ConstantNode} with a + * {@linkplain ConstantNode#getStableDimension() stable dimension} of 1. + */ + private void applyStable(StructuredGraph graph) { + if (graph.method().getDeclaringClass().toJavaName().equals(Test.class.getName())) { + SnippetReflectionProvider snippetReflection = getSnippetReflection(); + for (ConstantNode cn : graph.getNodes().filter(ConstantNode.class)) { + JavaConstant javaConstant = (JavaConstant) cn.getValue(); + Object obj = snippetReflection.asObject(Object.class, javaConstant); + if (StableArrays.contains(obj)) { + ConstantNode stableConstant = ConstantNode.forConstant(javaConstant, 1, cn.isDefaultStable(), getMetaAccess()); + cn.replace(graph, stableConstant); + break; + } + } + } + } + + private static void assertEQ(CompiledMethod compiledMethod, Object left, Object right) { + Assert.assertEquals(String.valueOf(compiledMethod.method), left, right); + } + + private static void assertNE(CompiledMethod compiledMethod, Object left, Object right) { + Assert.assertNotEquals(String.valueOf(compiledMethod.method), left, right); + } + + static class CompiledMethod { + final ResolvedJavaMethod method; + final InstalledCode code; + + CompiledMethod(ResolvedJavaMethod method, InstalledCode code) { + this.method = method; + this.code = code; + } + + Object call() throws InvalidInstalledCodeException { + return this.code.executeVarargs(); + } + } + + /** + * Compile the method called by the lambda wrapped by {@code c}. + */ + private CompiledMethod compile(Callable c) { + ResolvedJavaMethod m = getResolvedJavaMethod(c.getClass(), "call"); + StructuredGraph graph = parseEager(m, AllowAssumptions.NO); + List invokedMethods = StreamSupport.stream(graph.getInvokes().spliterator(), false).map((inv) -> inv.getTargetMethod()).collect(Collectors.toList()); + Assert.assertEquals(String.valueOf(invokedMethods), 1, invokedMethods.size()); + ResolvedJavaMethod invokedMethod = invokedMethods.get(0); + return new CompiledMethod(invokedMethod, getCode(invokedMethods.get(0))); + } + + void run(Callable c, Runnable sameResultAction, Runnable changeResultAction) throws Exception { + Object first = c.call(); + CompiledMethod cm = compile(c); + + if (sameResultAction != null) { + sameResultAction.run(); + assertEQ(cm, first, cm.call()); + } + + if (changeResultAction != null) { + changeResultAction.run(); + assertNE(cm, first, cm.call()); + assertEQ(cm, cm.call(), cm.call()); + } + } + + /** + * Tests this sequence: + * + *
+     * 1. {@code res1 = c()}
+     * 2. Compile c.
+     * 3. Change stable array element read by c.
+     * 4. {@code res2 = c()}
+     * 5. {@code assert Objects.equals(res1, res2)}
+     * 
+ * + * That is, tests that compiling a method with an unsafe read of a stable array element folds + * the element value into the compiled code. + * + * @param c a handle to one of the methods in {@link Test} + * @param setDefaultAction a method that when invoked will change the value of the array element + * read by {@code c} + */ + void testMatched(Callable c, Runnable setDefaultAction) throws Exception { + run(c, setDefaultAction, null); + Setter.reset(); + } + + /** + * Tests this sequence: + * + *
+     * 1. {@code res1 = c()}
+     * 2. Compile c.
+     * 3. Change stable array element read by c.
+     * 4. {@code res2 = c()}
+     * 5. {@code assert !Objects.equals(res1, res2)}
+     * 
+ * + * That is, tests that compiling a method with an unsafe read of a stable array element does not + * fold the element value into the compiled code. + * + * @param c a handle to one of the methods in {@link Test} + * @param setDefaultAction a method that when invoked will change the value of the array element + * read by {@code c} + */ + void testMismatched(Callable c, Runnable setDefaultAction) throws Exception { + run(c, null, setDefaultAction); + Setter.reset(); + } + + void testUnsafeAccess() throws Exception { + // boolean[], aligned accesses + testMatched(Test::testZ_Z, Test::changeZ); + testMatched(Test::testZ_B, Test::changeZ); + testMatched(Test::testZ_S, Test::changeZ); + testMatched(Test::testZ_C, Test::changeZ); + testMatched(Test::testZ_I, Test::changeZ); + testMatched(Test::testZ_J, Test::changeZ); + testMatched(Test::testZ_F, Test::changeZ); + testMatched(Test::testZ_D, Test::changeZ); + + // byte[], aligned accesses + testMatched(Test::testB_Z, Test::changeB); + testMatched(Test::testB_B, Test::changeB); + testMatched(Test::testB_S, Test::changeB); + testMatched(Test::testB_C, Test::changeB); + testMatched(Test::testB_I, Test::changeB); + testMatched(Test::testB_J, Test::changeB); + testMatched(Test::testB_F, Test::changeB); + testMatched(Test::testB_D, Test::changeB); + + // short[], aligned accesses + testMatched(Test::testS_Z, Test::changeS); + testMatched(Test::testS_B, Test::changeS); + testMatched(Test::testS_S, Test::changeS); + testMatched(Test::testS_C, Test::changeS); + testMatched(Test::testS_I, Test::changeS); + testMatched(Test::testS_J, Test::changeS); + testMatched(Test::testS_F, Test::changeS); + testMatched(Test::testS_D, Test::changeS); + + // char[], aligned accesses + testMatched(Test::testC_Z, Test::changeC); + testMatched(Test::testC_B, Test::changeC); + testMatched(Test::testC_S, Test::changeC); + testMatched(Test::testC_C, Test::changeC); + testMatched(Test::testC_I, Test::changeC); + testMatched(Test::testC_J, Test::changeC); + testMatched(Test::testC_F, Test::changeC); + testMatched(Test::testC_D, Test::changeC); + + // int[], aligned accesses + testMatched(Test::testI_Z, Test::changeI); + testMatched(Test::testI_B, Test::changeI); + testMatched(Test::testI_S, Test::changeI); + testMatched(Test::testI_C, Test::changeI); + testMatched(Test::testI_I, Test::changeI); + testMatched(Test::testI_J, Test::changeI); + testMatched(Test::testI_F, Test::changeI); + testMatched(Test::testI_D, Test::changeI); + + // long[], aligned accesses + testMatched(Test::testJ_Z, Test::changeJ); + testMatched(Test::testJ_B, Test::changeJ); + testMatched(Test::testJ_S, Test::changeJ); + testMatched(Test::testJ_C, Test::changeJ); + testMatched(Test::testJ_I, Test::changeJ); + testMatched(Test::testJ_J, Test::changeJ); + testMatched(Test::testJ_F, Test::changeJ); + testMatched(Test::testJ_D, Test::changeJ); + + // float[], aligned accesses + testMatched(Test::testF_Z, Test::changeF); + testMatched(Test::testF_B, Test::changeF); + testMatched(Test::testF_S, Test::changeF); + testMatched(Test::testF_C, Test::changeF); + testMatched(Test::testF_I, Test::changeF); + testMatched(Test::testF_J, Test::changeF); + testMatched(Test::testF_F, Test::changeF); + testMatched(Test::testF_D, Test::changeF); + + // double[], aligned accesses + testMatched(Test::testD_Z, Test::changeD); + testMatched(Test::testD_B, Test::changeD); + testMatched(Test::testD_S, Test::changeD); + testMatched(Test::testD_C, Test::changeD); + testMatched(Test::testD_I, Test::changeD); + testMatched(Test::testD_J, Test::changeD); + testMatched(Test::testD_F, Test::changeD); + testMatched(Test::testD_D, Test::changeD); + + // Object[], aligned accesses + testMatched(Test::testL_L, Test::changeL); + testMismatched(Test::testL_J, Test::changeL); // long & double are always as large as an OOP + testMismatched(Test::testL_D, Test::changeL); + + // Unaligned accesses + testMismatched(Test::testS_U, Test::changeS); + testMismatched(Test::testC_U, Test::changeC); + testMismatched(Test::testI_U, Test::changeI); + testMismatched(Test::testJ_U, Test::changeJ); + } + + @org.junit.Test + public void main() throws Exception { + testUnsafeAccess(); + } +} diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java index 66219aeaec90..60bebd7b9e19 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java @@ -32,6 +32,8 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -57,6 +59,7 @@ import org.graalvm.compiler.api.test.ModuleSupport; import org.graalvm.compiler.bytecode.BridgeMethodUtils; import org.graalvm.compiler.core.CompilerThreadFactory; +import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.type.ArithmeticOpTable; import org.graalvm.compiler.debug.DebugCloseable; @@ -74,6 +77,9 @@ import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; import org.graalvm.compiler.nodes.java.LoadFieldNode; +import org.graalvm.compiler.nodes.memory.MemoryKill; +import org.graalvm.compiler.nodes.memory.MultiMemoryKill; +import org.graalvm.compiler.nodes.memory.SingleMemoryKill; import org.graalvm.compiler.nodes.spi.CoreProviders; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionDescriptor; @@ -153,6 +159,10 @@ protected String getClassPath() { classpath = System.getProperty("sun.boot.class.path"); } else { classpath = JRT_CLASS_PATH_ENTRY; + String upgradeModulePath = System.getProperty("jdk.module.upgrade.path"); + if (upgradeModulePath != null) { + classpath += File.pathSeparator + upgradeModulePath; + } } // Also process classes that go into the libgraal native image. @@ -277,39 +287,43 @@ public static void runTest(InvariantsTool tool) { if (path.equals(JRT_CLASS_PATH_ENTRY)) { for (String className : ModuleSupport.getJRTGraalClassNames()) { if (isGSON(className)) { - /* - * GSON classes are compiled with old JDK - */ continue; } classNames.add(className); } } else { - final ZipFile zipFile = new ZipFile(new File(path)); - for (final Enumeration entry = zipFile.entries(); entry.hasMoreElements();) { - final ZipEntry zipEntry = entry.nextElement(); - String name = zipEntry.getName(); - if (name.endsWith(".class") && !name.startsWith("META-INF/versions/")) { - String className = name.substring(0, name.length() - ".class".length()).replace('/', '.'); - if (isInNativeImage(className)) { - /* - * Native Image is an external tool and does not need to follow - * the Graal invariants. - */ - continue; + File file = new File(path); + if (!file.exists()) { + continue; + } + if (file.isDirectory()) { + Path root = file.toPath(); + Files.walk(root).forEach(p -> { + String name = root.relativize(p).toString(); + if (name.endsWith(".class") && !name.startsWith("META-INF/versions/")) { + String className = name.substring(0, name.length() - ".class".length()).replace('/', '.'); + if (!(isInNativeImage(className) || isGSON(className))) { + classNames.add(className); + } } - if (isGSON(className)) { - /* - * GSON classes are compiled with old JDK - */ - continue; + }); + } else { + final ZipFile zipFile = new ZipFile(file); + for (final Enumeration entry = zipFile.entries(); entry.hasMoreElements();) { + final ZipEntry zipEntry = entry.nextElement(); + String name = zipEntry.getName(); + if (name.endsWith(".class") && !name.startsWith("META-INF/versions/")) { + String className = name.substring(0, name.length() - ".class".length()).replace('/', '.'); + if (isInNativeImage(className) || isGSON(className)) { + continue; + } + classNames.add(className); } - classNames.add(className); } } } } catch (IOException ex) { - Assert.fail(ex.toString()); + throw new AssertionError(ex); } } } @@ -530,15 +544,25 @@ private static void collectOptionFieldUsages(Map errors, Map> optionFieldUsages) { for (Map.Entry> e : optionFieldUsages.entrySet()) { if (e.getValue().isEmpty()) { - errors.add("No uses found for " + e.getKey().format("%H.%n")); + if (e.getKey().format("%H.%n").equals(GraalOptions.VerifyPhases.getDescriptor().getLocation())) { + // Special case: This option may only have downstream uses + } else { + errors.add("No uses found for " + e.getKey().format("%H.%n")); + } } } } + /** + * Native Image is an external tool and does not need to follow the Graal invariants. + */ private static boolean isInNativeImage(String className) { return className.startsWith("org.graalvm.nativeimage"); } + /** + * GSON classes are compiled with old JDK. + */ private static boolean isGSON(String className) { return className.contains("com.google.gson"); } @@ -579,6 +603,10 @@ private static void checkClass(Class c, MetaAccessProvider metaAccess, List verifier : verifiers) { verifier.verifyClass(c, metaAccess); diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopMaxTripCountPiTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopMaxTripCountPiTest.java new file mode 100644 index 000000000000..4f7b9f8e2335 --- /dev/null +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopMaxTripCountPiTest.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.core.test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.nodes.BeginNode; +import org.graalvm.compiler.nodes.NodeView; +import org.graalvm.compiler.nodes.PiNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; +import org.graalvm.compiler.nodes.loop.LoopEx; +import org.graalvm.compiler.nodes.loop.LoopsData; +import org.graalvm.compiler.options.OptionValues; +import org.junit.Assert; +import org.junit.Test; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Test to verify that loop max trip count nodes reuse existing {@link PiNode}s if possible. + */ +public class CountedLoopMaxTripCountPiTest extends GraalCompilerTest { + + public static int guardLoopEntered(boolean condition, int guardedValue) { + if (condition) { + GraalDirectives.deoptimize(); + } + return positivePi(guardedValue); + } + + // intrinsified below + public static int positivePi(int n) { + return n; + } + + @Override + protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) { + super.registerInvocationPlugins(invocationPlugins); + Registration r = new Registration(invocationPlugins, CountedLoopMaxTripCountPiTest.class); + + r.register1("positivePi", int.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, Receiver receiver, ValueNode n) { + BeginNode begin = b.add(new BeginNode()); + b.addPush(JavaKind.Int, PiNode.create(n, StampFactory.positiveInt().improveWith(n.stamp(NodeView.DEFAULT)), begin)); + return true; + } + }); + } + + int ascendingSnippet(int start, int limit) { + int maxTripCount = guardLoopEntered(limit < start, limit - start); + int sum = 0; + for (int i = start; GraalDirectives.injectIterationCount(101, i < limit); i++) { + GraalDirectives.sideEffect(i); + sum += i; + } + return sum + maxTripCount; + } + + int descendingSnippet(int start, int limit) { + int maxTripCount = guardLoopEntered(start < limit, start - limit + 1); + int sum = 0; + for (int i = start; GraalDirectives.injectIterationCount(102, i >= limit); i--) { + GraalDirectives.sideEffect(i); + sum += i; + } + return sum + maxTripCount; + } + + /** + * In the high and mid tiers, make sure that all max trip count nodes are the unique pi node in + * the graph (i.e., exactly the one proved by the guard). We don't check the low tier because pi + * nodes are eliminated by FixReads. + */ + void checkGraph(StructuredGraph graph, LoopsData loops) { + loops.detectedCountedLoops(); + for (LoopEx loop : loops.loops()) { + Assert.assertTrue("expect all loops to be counted", loop.isCounted()); + ValueNode maxTripCountNode = loop.counted().maxTripCountNode(); + Assert.assertTrue("expect a PiNode for the guarded maxTripCount, got: " + maxTripCountNode, maxTripCountNode instanceof PiNode); + } + PiNode[] pis = graph.getNodes().filter(PiNode.class).snapshot().toArray(new PiNode[0]); + Assert.assertEquals("number of PiNodes in the graph", 1, pis.length); + } + + @Override + protected void checkHighTierGraph(StructuredGraph graph) { + super.checkHighTierGraph(graph); + checkGraph(graph, getDefaultHighTierContext().getLoopsDataProvider().getLoopsData(graph)); + } + + @Override + protected void checkMidTierGraph(StructuredGraph graph) { + super.checkMidTierGraph(graph); + checkGraph(graph, getDefaultMidTierContext().getLoopsDataProvider().getLoopsData(graph)); + } + + protected void testLoop(String snippetName, Object... args) { + OptionValues options = new OptionValues(getInitialOptions(), GraalOptions.PartialUnroll, false, GraalOptions.LoopPeeling, false); + test(options, snippetName, args); + } + + @Test + public void testAscending() { + testLoop("ascendingSnippet", 0, 100); + } + + @Test + public void testDescending() { + testLoop("descendingSnippet", 100, 0); + } +} diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DumpPathTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DumpPathTest.java index 628d39f367e6..880b253bb62a 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DumpPathTest.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DumpPathTest.java @@ -32,6 +32,7 @@ import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.debug.DebugOptions; +import org.graalvm.compiler.debug.TTY; import org.graalvm.compiler.debug.DebugOptions.PrintGraphTarget; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; @@ -47,21 +48,25 @@ public static Object snippet() { return new String("snippet"); } + @SuppressWarnings("try") @Test - public void testDump() throws IOException { + public void testDump() throws Exception { assumeManagementLibraryIsLoadable(); try (TemporaryDirectory temp = new TemporaryDirectory(Paths.get("."), "DumpPathTest")) { String[] extensions = new String[]{".cfg", ".bgv", ".graph-strings"}; EconomicMap, Object> overrides = OptionValues.newOptionMap(); overrides.put(DebugOptions.DumpPath, temp.toString()); + overrides.put(DebugOptions.ShowDumpFiles, false); overrides.put(DebugOptions.PrintCFG, true); overrides.put(DebugOptions.PrintGraph, PrintGraphTarget.File); overrides.put(DebugOptions.PrintCanonicalGraphStrings, true); overrides.put(DebugOptions.Dump, "*"); overrides.put(DebugOptions.MethodFilter, null); - // Generate dump files. - test(new OptionValues(getInitialOptions(), overrides), "snippet"); + try (AutoCloseable c = new TTY.Filter()) { + // Generate dump files. + test(new OptionValues(getInitialOptions(), overrides), "snippet"); + } // Check that IGV files got created, in the right place. checkForFiles(temp.path, extensions); } diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java index b5ec3198abd5..94eaf3642c3a 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java @@ -70,7 +70,6 @@ import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.NodeMap; import org.graalvm.compiler.java.BytecodeParser; -import org.graalvm.compiler.java.ComputeLoopFrequenciesClosure; import org.graalvm.compiler.java.GraphBuilderPhase; import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; import org.graalvm.compiler.lir.phases.LIRSuites; @@ -266,23 +265,6 @@ protected Suites createSuites(OptionValues opts) { */ iter = ret.getHighTier().findPhase(CanonicalizerPhase.class); } - iter.add(new Phase() { - - @Override - protected void run(StructuredGraph graph) { - ComputeLoopFrequenciesClosure.compute(graph); - } - - @Override - public float codeSizeIncrease() { - return NodeSize.IGNORE_SIZE_CONTRACT_FACTOR; - } - - @Override - protected CharSequence getName() { - return "ComputeLoopFrequenciesPhase"; - } - }); ret.getHighTier().appendPhase(new Phase() { @Override @@ -496,8 +478,8 @@ protected void assertConstantReturn(StructuredGraph graph, int value) { } protected static String getCanonicalGraphString(StructuredGraph graph, boolean excludeVirtual, boolean checkConstants) { - SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST); - schedule.apply(graph); + SchedulePhase.runWithoutContextOptimizations(graph, SchedulingStrategy.EARLIEST); + ScheduleResult scheduleResult = graph.getLastSchedule(); NodeMap canonicalId = graph.createNodeMap(); @@ -575,8 +557,7 @@ private static int filteredUsageCount(Node node) { * @return a scheduled textual dump of {@code graph} . */ protected static String getScheduledGraphString(StructuredGraph graph) { - SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER); - schedule.apply(graph); + SchedulePhase.runWithoutContextOptimizations(graph, SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER); ScheduleResult scheduleResult = graph.getLastSchedule(); StringBuilder result = new StringBuilder(); diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphScheduleTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphScheduleTest.java index 6d4eaa4d8171..dcae927ece3d 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphScheduleTest.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphScheduleTest.java @@ -43,8 +43,7 @@ protected void assertOrderedAfterSchedule(StructuredGraph graph, Node a, Node b) } protected void assertOrderedAfterSchedule(StructuredGraph graph, SchedulePhase.SchedulingStrategy strategy, Node a, Node b) { - SchedulePhase ibp = new SchedulePhase(strategy); - ibp.apply(graph); + SchedulePhase.runWithoutContextOptimizations(graph, strategy); assertOrderedAfterLastSchedule(graph, a, b); } diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardPrioritiesTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardPrioritiesTest.java index 1f50d8435ed8..0ad459b9021f 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardPrioritiesTest.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardPrioritiesTest.java @@ -111,7 +111,7 @@ public void unknownTest() { assumeTrue("GuardPriorities must be turned one", GraalOptions.GuardPriorities.getValue(getInitialOptions())); StructuredGraph graph = prepareGraph("unknownCondition"); - new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER).apply(graph); + new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER).apply(graph, getDefaultHighTierContext()); for (GuardNode g1 : graph.getNodes(GuardNode.TYPE)) { for (GuardNode g2 : graph.getNodes(GuardNode.TYPE)) { if (g1.getSpeculation().equals(SpeculationLog.NO_SPECULATION) ^ g2.getSpeculation().equals(SpeculationLog.NO_SPECULATION)) { diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IntegerBoxEqualsTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IntegerBoxEqualsTest.java index 97b8ab13cc99..2d53f24f18f5 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IntegerBoxEqualsTest.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IntegerBoxEqualsTest.java @@ -24,13 +24,14 @@ */ package org.graalvm.compiler.core.test; +import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.nodes.IfNode; import org.graalvm.compiler.nodes.calc.ObjectEqualsNode; import org.junit.Test; import jdk.vm.ci.meta.ResolvedJavaMethod; -public class IntegerBoxEqualsTest extends SubprocessTest { +public class IntegerBoxEqualsTest extends GraalCompilerTest { class Cell { private final Integer value; @@ -40,11 +41,16 @@ class Cell { } public String check(Integer i) { - if (value == i || value.equals(i)) { - return ""; - } else { + b: { + if (GraalDirectives.injectBranchProbability(0.01, value == i)) { + break b; + } + if (value.equals(i)) { + break b; + } return "nope"; } + return ""; } } @@ -65,6 +71,9 @@ public void cellTest() { test(get, null, cell, value); final int equalsCount = lastCompiledGraph.getNodes().filter(ObjectEqualsNode.class).count(); final int ifCount = lastCompiledGraph.getNodes().filter(IfNode.class).count(); + if (!(equalsCount == 0 || ifCount > 1)) { + lastCompiledGraph.getDebug().forceDump(lastCompiledGraph, "There must be no reference comparisons in the graph, or everything reachable in equals."); + } assertTrue(equalsCount == 0 || ifCount > 1, "There must be no reference comparisons in the graph, or everything reachable in equals."); } diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java index 021cdd58f715..96ac33582e24 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java @@ -80,7 +80,7 @@ private void longAddChain(boolean reverse) { graph.start().setNext(returnNode); for (SchedulingStrategy s : Strategies) { - new SchedulePhase(s).apply(graph); + SchedulePhase.runWithoutContextOptimizations(graph, s); } this.createCanonicalizerPhase().apply(graph, context); diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryScheduleTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryScheduleTest.java index 55b8feda603b..92e7914468db 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryScheduleTest.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryScheduleTest.java @@ -718,7 +718,7 @@ private ScheduleResult getFinalSchedule(final String snippet, final TestMode mod new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER).apply(graph, midContext); SchedulePhase schedule = new SchedulePhase(schedulingStrategy); - schedule.apply(graph); + schedule.apply(graph, getDefaultLowTierContext()); return graph.getLastSchedule(); } catch (Throwable e) { throw debug.handle(e); diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MulNegateTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MulNegateTest.java new file mode 100644 index 000000000000..90d68978af95 --- /dev/null +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MulNegateTest.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.core.test; + +import org.graalvm.compiler.nodes.calc.NegateNode; +import org.junit.Test; + +public class MulNegateTest extends GraalCompilerTest { + + public static final int[] INT_TEST_VALUES = {0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE}; + + public static int mulInt(int x, int y) { + return -x * -y; + } + + @Test + public void testInt() { + assertTrue(getFinalGraph("mulInt").getNodes().filter(NegateNode.class).count() == 0); + + for (int i : INT_TEST_VALUES) { + for (int j : INT_TEST_VALUES) { + test("mulInt", i, j); + } + } + } + + public static final long[] LONG_TEST_VALUES = {0L, 1L, -1L, Long.MIN_VALUE, Long.MAX_VALUE}; + + public static long mulLong(long x, long y) { + return -x * -y; + } + + @Test + public void testLong() { + assertTrue(getFinalGraph("mulLong").getNodes().filter(NegateNode.class).count() == 0); + + for (long i : LONG_TEST_VALUES) { + for (long j : LONG_TEST_VALUES) { + test("mulLong", i, j); + } + } + } + + public static final float[] FLOAT_TEST_VALUES = {0.0f, -0.0f, 1.0f, -1.0f, Float.MIN_VALUE, Float.MIN_NORMAL, + Float.MAX_VALUE, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, Float.NaN}; + + public static float mulFloat(float x, float y) { + return -x * -y; + } + + @Test + public void testFloat() { + assertTrue(getFinalGraph("mulFloat").getNodes().filter(NegateNode.class).count() == 0); + + for (float i : FLOAT_TEST_VALUES) { + for (float j : FLOAT_TEST_VALUES) { + test("mulFloat", i, j); + } + } + } + + public static final double[] DOUBLE_TEST_VALUES = {0.0d, -0.0d, 1.0d, -1.0d, Double.MIN_VALUE, Double.MIN_NORMAL, + Double.MAX_VALUE, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.NaN}; + + public static double mulDouble(double x, double y) { + return -x * -y; + } + + @Test + public void testDouble() { + assertTrue(getFinalGraph("mulDouble").getNodes().filter(NegateNode.class).count() == 0); + + for (double i : DOUBLE_TEST_VALUES) { + for (double j : DOUBLE_TEST_VALUES) { + test("mulDouble", i, j); + } + } + } +} diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java index 472ab5aea744..42b1b325dffe 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java @@ -27,13 +27,13 @@ import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.iterators.NodeIterable; -import org.graalvm.compiler.nodes.spi.Canonicalizable; -import org.graalvm.compiler.nodes.spi.SimplifierTool; -import org.graalvm.compiler.java.ComputeLoopFrequenciesClosure; import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; +import org.graalvm.compiler.nodes.spi.Canonicalizable; import org.graalvm.compiler.nodes.spi.CoreProviders; +import org.graalvm.compiler.nodes.spi.SimplifierTool; import org.graalvm.compiler.phases.BasePhase; import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.common.CanonicalizerPhase.CustomSimplification; @@ -177,14 +177,12 @@ public void testCanonicalizationExample() { private void prepareGraphForLoopFrequencies(StructuredGraph g, HighTierContext htc) { // let canonicalizer work away branch probability nodes createCanonicalizerPhase().apply(g, htc); - // recompute the loop frequencies - ComputeLoopFrequenciesClosure.compute(g); } private static void assertFrequency(StructuredGraph g, int iterations) { NodeIterable loopBeginNodes = g.getNodes(LoopBeginNode.TYPE); LoopBeginNode loopBeginNode = loopBeginNodes.first(); - Assert.assertEquals("loop frequency of " + loopBeginNode, iterations, loopBeginNode.loopFrequency(), 0); + Assert.assertEquals("loop frequency of " + loopBeginNode, iterations, ControlFlowGraph.compute(g, false, false, false, false).localLoopFrequency(loopBeginNode), 0); } @Test diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReentrantBlockIteratorTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReentrantBlockIteratorTest.java index d0216e1a7e90..4443313e5e84 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReentrantBlockIteratorTest.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReentrantBlockIteratorTest.java @@ -244,7 +244,7 @@ protected List processLoop(Loop loop, VoidState initialState) ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, false); ReentrantBlockIterator.apply(closure, cfg.getStartBlock()); // schedule for IGV - new SchedulePhase(graph.getOptions()).apply(graph); + SchedulePhase.runWithoutContextOptimizations(graph); return blocks; } diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest.java index d43d6a3c2148..de17b0293ee8 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest.java @@ -64,7 +64,7 @@ public void testValueProxyInputs() { } graph.clearAllStateAfter(); SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.LATEST); - schedulePhase.apply(graph); + schedulePhase.apply(graph, getDefaultHighTierContext()); ScheduleResult schedule = graph.getLastSchedule(); NodeMap nodeToBlock = schedule.getCFG().getNodeToBlock(); assertTrue(graph.getNodes().filter(LoopExitNode.class).count() == 1); diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java index 380b3e3390e5..cf343b349622 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java @@ -72,7 +72,7 @@ public void testValueProxyInputs() { beginNode.setNext(returnNode); debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph"); SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER); - schedulePhase.apply(graph); + schedulePhase.apply(graph, getDefaultHighTierContext()); ScheduleResult schedule = graph.getLastSchedule(); BlockMap> blockToNodesMap = schedule.getBlockToNodesMap(); NodeMap nodeToBlock = schedule.getNodeToBlockMap(); @@ -106,7 +106,7 @@ public void testValueProxyInputs() { FrameStateAssignmentPhase phase = new FrameStateAssignmentPhase(); phase.apply(graph); - schedulePhase.apply(graph); + schedulePhase.apply(graph, midContext); schedule = graph.getLastSchedule(); blockToNodesMap = schedule.getBlockToNodesMap(); nodeToBlock = schedule.getNodeToBlockMap(); diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SimpleCFGTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SimpleCFGTest.java index 2c90d3408a77..2b997db480b6 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SimpleCFGTest.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SimpleCFGTest.java @@ -24,13 +24,24 @@ */ package org.graalvm.compiler.core.test; +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.common.PermanentBailoutException; +import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugContext.Builder; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeCycles; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodeinfo.NodeSize; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.AbstractMergeNode; import org.graalvm.compiler.nodes.BeginNode; +import org.graalvm.compiler.nodes.ControlSplitNode; import org.graalvm.compiler.nodes.EndNode; +import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.LoopExitNode; import org.graalvm.compiler.nodes.MergeNode; import org.graalvm.compiler.nodes.ProfileData.BranchProbabilityData; import org.graalvm.compiler.nodes.ReturnNode; @@ -38,6 +49,8 @@ import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; import org.graalvm.compiler.nodes.cfg.Block; import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; +import org.graalvm.compiler.nodes.debug.ControlFlowAnchored; +import org.graalvm.compiler.nodes.extended.BranchProbabilityNode; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.printer.GraalDebugHandlersFactory; import org.junit.Assert; @@ -50,6 +63,132 @@ private static void dumpGraph(final StructuredGraph graph) { debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph"); } + @NodeInfo(allowedUsageTypes = InputType.Anchor, cycles = NodeCycles.CYCLES_0, size = NodeSize.SIZE_0) + static class SingleSplit extends ControlSplitNode implements ControlFlowAnchored { + public static final NodeClass TYPE = NodeClass.create(SingleSplit.class); + + @Successor AbstractBeginNode singleSuccessor; + + protected SingleSplit() { + super(TYPE, StampFactory.forVoid()); + } + + void setSingleSuccessor(AbstractBeginNode node) { + updatePredecessor(singleSuccessor, node); + singleSuccessor = node; + } + + @Override + public double probability(AbstractBeginNode successor) { + return getProfileData().getDesignatedSuccessorProbability(); + } + + @Override + public int getSuccessorCount() { + return 1; + } + + @Override + public boolean setProbability(AbstractBeginNode successor, BranchProbabilityData profileData) { + throw new PermanentBailoutException("There is only one successor, so probability cannot change"); + } + + @Override + public BranchProbabilityData getProfileData() { + return BranchProbabilityNode.ALWAYS_TAKEN_PROFILE; + } + + @Override + public AbstractBeginNode getPrimarySuccessor() { + return singleSuccessor; + } + + } + + static int single() { + GraalDirectives.deoptimizeAndInvalidate(); + return -1; + } + + @Test + public void testSingleSplit() { + StructuredGraph g = parseEager(getResolvedJavaMethod("single"), AllowAssumptions.NO); + FixedNode next = g.start().next(); + g.start().setNext(null); + SingleSplit s = g.add(new SingleSplit()); + AbstractBeginNode b = g.add(new BeginNode()); + b.setNext(next); + s.setSingleSuccessor(b); + g.start().setNext(s); + + g.getDebug().dump(DebugContext.VERY_DETAILED_LEVEL, g, "after build"); + ControlFlowGraph.compute(g, true, true, true, true); + } + + static int singleLoop(int end) { + int i = 0; + while (true) { + switch (i) { + default: + } + if (i == end) { + break; + } + i++; + continue; + } + return i; + } + + @Test + public void testSingleSplitLoop() { + StructuredGraph g = parseEager(getResolvedJavaMethod("singleLoop"), AllowAssumptions.NO); + g.getDebug().dump(DebugContext.VERY_DETAILED_LEVEL, g, "after build"); + ControlFlowGraph.compute(g, true, true, true, true); + } + + static int foo(int a, int b) { + int res = 0; + int i = 0; + while (true) { + if (i >= a) { + break; + } + if (i == 123) { + GraalDirectives.deoptimizeAndInvalidate(); + } + if (i == 126) { + GraalDirectives.deoptimizeAndInvalidate(); + } + res += i; + i++; + } + if (b == 42) { + GraalDirectives.deoptimizeAndInvalidate(); + } + return res; + } + + @Override + protected void checkHighTierGraph(StructuredGraph graph) { + super.checkHighTierGraph(graph); + if (!modify) { + return; + } + for (LoopExitNode lex : graph.getNodes().filter(LoopExitNode.class)) { + lex.setStateAfter(lex.loopBegin().stateAfter()); + } + } + + private boolean modify = false; + + @Test + public void testFoo() { + modify = true; + test("foo", 12, 12); + modify = false; + } + @Test public void testImplies() { OptionValues options = getInitialOptions(); diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SpectreFenceTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SpectreFenceTest.java index 201de65bf866..c75cf4417726 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SpectreFenceTest.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SpectreFenceTest.java @@ -64,6 +64,7 @@ public static long test1Snippet(double a) { } else { SideEffectL = UNSAFE.getLong(m, ARRAY_LONG_BASE_OFFSET); } + GraalDirectives.controlFlowAnchor(); return UNSAFE.getLong(m, ARRAY_LONG_BASE_OFFSET); } @@ -75,7 +76,9 @@ public static long test2Snippet(double a) { } else { return Memory[1]; } + GraalDirectives.controlFlowAnchor(); } + GraalDirectives.controlFlowAnchor(); return Memory[2]; } @@ -88,6 +91,7 @@ public static long test3Snippet(double a) { return 1; } } + GraalDirectives.controlFlowAnchor(); return 4; } @@ -102,6 +106,7 @@ private void assertNumberOfFences(String snip, int fences) { if (beginNode.hasSpeculationFence()) { computedFences++; } + GraalDirectives.controlFlowAnchor(); } Assert.assertEquals("Expected fences", fences, computedFences); } diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StableArrayReadFoldingTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StableArrayReadFoldingTest.java index 2fed2cb69022..f2e515a13a3f 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StableArrayReadFoldingTest.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StableArrayReadFoldingTest.java @@ -24,20 +24,21 @@ */ package org.graalvm.compiler.core.test; -import jdk.vm.ci.amd64.AMD64; -import jdk.vm.ci.meta.ResolvedJavaMethod; +import java.util.stream.IntStream; import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.options.OptionValues; -import org.junit.Assume; import org.junit.Test; +import jdk.vm.ci.meta.ResolvedJavaMethod; + public class StableArrayReadFoldingTest extends GraalCompilerTest { + static final int FIRST_INT = 42; static final boolean[] STABLE_BOOLEAN_ARRAY = new boolean[16]; - static final int[] STABLE_INT_ARRAY = new int[16]; + static final int[] STABLE_INT_ARRAY = IntStream.range(FIRST_INT, FIRST_INT + 16).toArray(); static final long BOOLEAN_ARRAY_BASE_OFFSET; static final long INT_ARRAY_BASE_OFFSET; @@ -95,30 +96,34 @@ public static boolean killWithSameTypeUnaligned() { STABLE_INT_ARRAY[0] = 0x01020304; int afterKill = UNSAFE.getInt(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1); - STABLE_INT_ARRAY[0] = 0; + STABLE_INT_ARRAY[0] = FIRST_INT; return beforeKill == afterKill; } + /** + * Checks that unaligned reads are not constant folded. + */ @Test public void testKillWithSameTypeUnaligned() { - Assume.assumeTrue("Only test unaligned access on AMD64", getTarget().arch instanceof AMD64); ResolvedJavaMethod method = getResolvedJavaMethod("killWithSameTypeUnaligned"); - testAgainstExpected(method, new Result(true, null), null); + testAgainstExpected(method, new Result(false, null), null); } public static boolean killWithDifferentTypeUnaligned() { - byte beforeKill = UNSAFE.getByte(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1); + short beforeKill = UNSAFE.getShort(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1); STABLE_INT_ARRAY[0] = 0x01020304; - byte afterKill = UNSAFE.getByte(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1); + short afterKill = UNSAFE.getShort(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1); - STABLE_INT_ARRAY[0] = 0; + STABLE_INT_ARRAY[0] = FIRST_INT; return beforeKill == afterKill; } + /** + * Checks that unaligned reads are not constant folded. + */ @Test public void testKillWithDifferentTypeUnaligned() { - Assume.assumeTrue("Only test unaligned access on AMD64", getTarget().arch instanceof AMD64); ResolvedJavaMethod method = getResolvedJavaMethod("killWithDifferentTypeUnaligned"); - testAgainstExpected(method, new Result(true, null), null); + testAgainstExpected(method, new Result(false, null), null); } } diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StampMemoryAccessTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StampMemoryAccessTest.java index 033d97d36bdc..f5ce3cf893c6 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StampMemoryAccessTest.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StampMemoryAccessTest.java @@ -24,8 +24,11 @@ */ package org.graalvm.compiler.core.test; +import java.lang.reflect.Field; + import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; +import org.junit.Assert; import org.junit.Test; import jdk.vm.ci.meta.JavaConstant; @@ -33,12 +36,16 @@ import jdk.vm.ci.meta.MemoryAccessProvider; /** - * + * Tests {@link MemoryAccessProvider#readObjectConstant} and + * {@link MemoryAccessProvider#readPrimitiveConstant} by way of {@link Stamp#readConstant}. */ public class StampMemoryAccessTest extends GraalCompilerTest { + long longField1 = Double.doubleToRawLongBits(Double.MAX_VALUE); + long longField2 = Double.doubleToRawLongBits(Double.MIN_VALUE); + @Test - public void testReadPrimitive() { + public void testReadPrimitiveOutOfBounds() { MemoryAccessProvider memory = getConstantReflection().getMemoryAccessProvider(); Stamp stamp = StampFactory.forKind(JavaKind.Long); JavaConstant objectBase = getSnippetReflection().forObject(""); @@ -48,7 +55,7 @@ public void testReadPrimitive() { } @Test - public void testReadObject() { + public void testReadObjectOutOfBounds() { MemoryAccessProvider memory = getConstantReflection().getMemoryAccessProvider(); Stamp stamp = StampFactory.forKind(JavaKind.Object); JavaConstant objectBase = getSnippetReflection().forObject(""); @@ -56,4 +63,25 @@ public void testReadObject() { JavaConstant arrayBase = getSnippetReflection().forObject(new int[]{}); assertTrue(stamp.readConstant(memory, arrayBase, 128) == null); } + + /** + * Checks that unaligned reads are not constant folded. + */ + @Test + public void testReadPrimitiveUnaligned() throws Exception { + MemoryAccessProvider memory = getConstantReflection().getMemoryAccessProvider(); + Object object = this; + JavaConstant objectBase = getSnippetReflection().forObject(object); + Field f = getClass().getDeclaredField("longField1"); + long baseDisplacement = UNSAFE.objectFieldOffset(f); + for (JavaKind kind : JavaKind.values()) { + if (kind.isPrimitive() && kind != JavaKind.Void && kind.getByteCount() > 1) { + for (long offset = 1; offset < kind.getByteCount(); offset++) { + long displacement = baseDisplacement + offset; + Stamp stamp = StampFactory.forKind(kind); + Assert.assertEquals(null, stamp.readConstant(memory, objectBase, displacement)); + } + } + } + } } diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java index 05c2f94a1d89..44aa8ad47b67 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java @@ -209,8 +209,7 @@ protected void assertEquals(StructuredGraph expected, StructuredGraph graph) { public static void outputGraph(StructuredGraph graph, String message) { TTY.println("========================= " + message); - SchedulePhase schedulePhase = new SchedulePhase(graph.getOptions()); - schedulePhase.apply(graph); + SchedulePhase.runWithoutContextOptimizations(graph); ScheduleResult schedule = graph.getLastSchedule(); for (Block block : schedule.getCFG().getBlocks()) { TTY.print("Block " + block + " "); diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyUpdateUsages.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyUpdateUsages.java index e4fd9fc76940..de774d7e718d 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyUpdateUsages.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyUpdateUsages.java @@ -31,6 +31,7 @@ import org.graalvm.compiler.graph.Node.OptionalInput; import org.graalvm.compiler.graph.NodeInputList; import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.java.LoadFieldNode; import org.graalvm.compiler.nodes.java.MethodCallTargetNode; import org.graalvm.compiler.nodes.java.StoreFieldNode; @@ -43,7 +44,7 @@ /** * Try to ensure that methods which update {@link Input} or {@link OptionalInput} fields also - * include a call to {@link Node#updateUsages} or {@link Node#updateUsagesInterface}. + * include a call to {@link Node#updateUsages} or {@link ValueNode#updateUsagesInterface}. */ public class VerifyUpdateUsages extends VerifyPhase { @@ -92,9 +93,11 @@ protected void verify(StructuredGraph graph, CoreProviders context) { // Single input field update so just check for updateUsages // or updateUsagesInterface call ResolvedJavaType nodeType = context.getMetaAccess().lookupJavaType(Node.class); + ResolvedJavaType valueNodeType = context.getMetaAccess().lookupJavaType(ValueNode.class); for (MethodCallTargetNode call : graph.getNodes().filter(MethodCallTargetNode.class)) { ResolvedJavaMethod callee = call.targetMethod(); - if (callee.getDeclaringClass().equals(nodeType) && (callee.getName().equals("updateUsages") || callee.getName().equals("updateUsagesInterface"))) { + if ((callee.getDeclaringClass().equals(nodeType) && (callee.getName().equals("updateUsages"))) || + (callee.getDeclaringClass().equals(valueNodeType) && callee.getName().equals("updateUsagesInterface"))) { return; } } diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EscapeAnalysisTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EscapeAnalysisTest.java index 5706749921e5..b3d40e2393fd 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EscapeAnalysisTest.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EscapeAnalysisTest.java @@ -89,10 +89,10 @@ public void testMonitor() { testEscapeAnalysis("testMonitorSnippet", JavaConstant.forInt(0), false); } - @SuppressWarnings({"deprecation", "synchronization"}) + @SuppressWarnings({"synchronized", "deprecation"}) public static int testMonitorSnippet() { - Integer x = new Integer(0); - Double y = new Double(0); + Object x = new Integer(0); + Object y = new Double(0); Object z = new Object(); synchronized (x) { synchronized (y) { @@ -101,7 +101,7 @@ public static int testMonitorSnippet() { } } } - return x.intValue(); + return ((Integer) x).intValue(); } @Test @@ -113,16 +113,16 @@ public void testMonitor2() { * This test case differs from the last one in that it requires inlining within a synchronized * region. */ - @SuppressWarnings({"deprecation", "synchronization"}) + @SuppressWarnings({"synchronized", "deprecation"}) public static int testMonitor2Snippet() { - Integer x = new Integer(0); - Double y = new Double(0); + Object x = new Integer(0); + Object y = new Double(0); Object z = new Object(); synchronized (x) { synchronized (y) { synchronized (z) { notInlineable(); - return x.intValue(); + return ((Integer) x).intValue(); } } } @@ -471,7 +471,7 @@ public static Object testPeeledLoopSnippet() { public void testPeeledLoop() { prepareGraph("testPeeledLoopSnippet", false); new LoopPeelingPhase(new DefaultLoopPolicies()).apply(graph, getDefaultHighTierContext()); - new SchedulePhase(graph.getOptions()).apply(graph); + new SchedulePhase(graph.getOptions()).apply(graph, getDefaultHighTierContext()); } public static void testDeoptMonitorSnippetInner(Object o2, Object t, int i) { diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java index 019ebb93623f..95643b44be61 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package org.graalvm.compiler.core.test.ea; import java.lang.ref.SoftReference; +import java.lang.reflect.Array; import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.core.test.TypeSystemTest; @@ -129,6 +130,18 @@ public static Object test3Snippet(int a) { } } + @Test + public void testDynArray() { + testPartialEscapeAnalysis("testDynArraySnippet", 0, 0); + } + + public static Object testDynArraySnippet(int a) { + Object[] args = (Object[]) Array.newInstance(Object.class, 2); + args[0] = a; + args[1] = 42; + return (int) args[0] + (int) args[1]; + } + @Test public void testArrayCopy() { testPartialEscapeAnalysis("testArrayCopySnippet", 0, 0); diff --git a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/LIRCompilerBackend.java b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/LIRCompilerBackend.java index 66fa406fdee1..e6e17723389c 100644 --- a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/LIRCompilerBackend.java +++ b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/LIRCompilerBackend.java @@ -27,7 +27,6 @@ import java.util.Collection; import java.util.List; -import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.LIRGenerationPhase; import org.graalvm.compiler.core.LIRGenerationPhase.LIRGenerationContext; @@ -67,7 +66,6 @@ import jdk.vm.ci.meta.Assumptions; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.SpeculationLog; import jdk.vm.ci.meta.VMConstant; @@ -91,7 +89,6 @@ public static void emitBackEnd(StructuredGraph gra graph.getAssumptions(), graph.method(), graph.getMethods(), - graph.getFields(), graph.getSpeculationLog(), bytecodeSize, lirGen, @@ -199,7 +196,6 @@ public static void emitCode(Backend backend, Assumptions assumptions, ResolvedJavaMethod rootMethod, Collection inlinedMethods, - EconomicSet accessedFields, SpeculationLog speculationLog, int bytecodeSize, LIRGenerationResult lirGenRes, @@ -218,7 +214,6 @@ public static void emitCode(Backend backend, } if (rootMethod != null) { compilationResult.setMethods(rootMethod, inlinedMethods); - compilationResult.setFields(accessedFields); compilationResult.setBytecodeSize(bytecodeSize); } if (speculationLog != null) { diff --git a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/BaseTier.java b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/BaseTier.java index b577e522672a..ad9e6e57bf16 100644 --- a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/BaseTier.java +++ b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/BaseTier.java @@ -24,8 +24,6 @@ */ package org.graalvm.compiler.core.phases; -import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; - import org.graalvm.compiler.nodes.loop.DefaultLoopPolicies; import org.graalvm.compiler.nodes.loop.LoopPolicies; import org.graalvm.compiler.options.OptionValues; @@ -38,13 +36,7 @@ public LoopPolicies createLoopPolicies(@SuppressWarnings("unused") OptionValues return new DefaultLoopPolicies(); } - public CanonicalizerPhase createCanonicalizerPhase(OptionValues options) { - CanonicalizerPhase canonicalizer = null; - if (ImmutableCode.getValue(options)) { - canonicalizer = CanonicalizerPhase.createWithoutReadCanonicalization(); - } else { - canonicalizer = CanonicalizerPhase.create(); - } - return canonicalizer; + public CanonicalizerPhase createCanonicalizerPhase() { + return CanonicalizerPhase.create(); } } diff --git a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyCompilerConfiguration.java b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyCompilerConfiguration.java index 73ccbaca39a2..87fed39234b7 100644 --- a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyCompilerConfiguration.java +++ b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyCompilerConfiguration.java @@ -48,17 +48,17 @@ public class EconomyCompilerConfiguration implements CompilerConfiguration { @Override public PhaseSuite createHighTier(OptionValues options) { - return new EconomyHighTier(options); + return new EconomyHighTier(); } @Override public PhaseSuite createMidTier(OptionValues options) { - return new EconomyMidTier(options); + return new EconomyMidTier(); } @Override public PhaseSuite createLowTier(OptionValues options) { - return new EconomyLowTier(options); + return new EconomyLowTier(); } @Override diff --git a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyHighTier.java b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyHighTier.java index a2a83f2a095e..4950478c89c8 100644 --- a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyHighTier.java +++ b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyHighTier.java @@ -25,15 +25,14 @@ package org.graalvm.compiler.core.phases; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.common.LoweringPhase; import org.graalvm.compiler.phases.tiers.HighTierContext; public class EconomyHighTier extends BaseTier { - public EconomyHighTier(OptionValues options) { - CanonicalizerPhase canonicalizer = this.createCanonicalizerPhase(options); + public EconomyHighTier() { + CanonicalizerPhase canonicalizer = this.createCanonicalizerPhase(); appendPhase(canonicalizer); appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER, true)); } diff --git a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyLowTier.java b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyLowTier.java index b67add26ef31..4ef1d8ae2fe9 100644 --- a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyLowTier.java +++ b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyLowTier.java @@ -25,7 +25,6 @@ package org.graalvm.compiler.core.phases; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.common.ExpandLogicPhase; import org.graalvm.compiler.phases.common.IncrementalCanonicalizerPhase; @@ -35,8 +34,8 @@ public class EconomyLowTier extends BaseTier { - public EconomyLowTier(OptionValues options) { - CanonicalizerPhase canonicalizer = this.createCanonicalizerPhase(options); + public EconomyLowTier() { + CanonicalizerPhase canonicalizer = this.createCanonicalizerPhase(); appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER)); appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new ExpandLogicPhase())); appendPhase(new SchedulePhase(SchedulePhase.SchedulingStrategy.LATEST_OUT_OF_LOOPS)); diff --git a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyMidTier.java b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyMidTier.java index 3b6e136a7686..449032907ae9 100644 --- a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyMidTier.java +++ b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyMidTier.java @@ -25,7 +25,6 @@ package org.graalvm.compiler.core.phases; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase; import org.graalvm.compiler.phases.common.GuardLoweringPhase; @@ -37,8 +36,8 @@ public class EconomyMidTier extends BaseTier { - public EconomyMidTier(OptionValues options) { - CanonicalizerPhase canonicalizer = this.createCanonicalizerPhase(options); + public EconomyMidTier() { + CanonicalizerPhase canonicalizer = this.createCanonicalizerPhase(); appendPhase(new RemoveValueProxyPhase()); appendPhase(new LoopSafepointInsertionPhase()); appendPhase(new GuardLoweringPhase()); diff --git a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/HighTier.java b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/HighTier.java index f0090dcb2e26..8f764b74a58c 100644 --- a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/HighTier.java +++ b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/HighTier.java @@ -69,7 +69,7 @@ public static class Options { } public HighTier(OptionValues options) { - CanonicalizerPhase canonicalizer = createCanonicalizerPhase(options); + CanonicalizerPhase canonicalizer = createCanonicalizerPhase(); appendPhase(canonicalizer); if (NodeCounterPhase.Options.NodeCounters.getValue(options)) { diff --git a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/LowTier.java b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/LowTier.java index 67b8b0e5c0e3..9d48abf0ebd9 100644 --- a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/LowTier.java +++ b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/LowTier.java @@ -56,7 +56,7 @@ static class Options { } public LowTier(OptionValues options) { - CanonicalizerPhase canonicalizer = createCanonicalizerPhase(options); + CanonicalizerPhase canonicalizer = createCanonicalizerPhase(); CanonicalizerPhase canonicalizerWithoutGVN = canonicalizer.copyWithoutGVN(); if (Options.ProfileCompiledMethods.getValue(options)) { diff --git a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/MidTier.java b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/MidTier.java index 5ad2da686d68..285cb3490f3b 100644 --- a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/MidTier.java +++ b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/MidTier.java @@ -36,6 +36,7 @@ import static org.graalvm.compiler.core.common.SpectrePHTMitigations.NonDeoptGuardTargets; import static org.graalvm.compiler.core.common.SpectrePHTMitigations.Options.SpectrePHTBarriers; +import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.loop.phases.LoopPartialUnrollPhase; import org.graalvm.compiler.loop.phases.LoopPredicationPhase; import org.graalvm.compiler.loop.phases.LoopSafepointEliminationPhase; @@ -65,7 +66,7 @@ public class MidTier extends BaseTier { public MidTier(OptionValues options) { - CanonicalizerPhase canonicalizer = createCanonicalizerPhase(options); + CanonicalizerPhase canonicalizer = createCanonicalizerPhase(); appendPhase(new LockEliminationPhase()); @@ -102,6 +103,10 @@ public MidTier(OptionValues options) { appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER)); + if (GraalOptions.ConditionalElimination.getValue(options)) { + appendPhase(new IterativeConditionalEliminationPhase(canonicalizer, false)); + } + appendPhase(new OptimizeDivPhase()); appendPhase(new FrameStateAssignmentPhase()); diff --git a/compiler/src/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java b/compiler/src/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java index fab940ca425f..bdd24a8a3665 100644 --- a/compiler/src/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java +++ b/compiler/src/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java @@ -84,6 +84,21 @@ */ public final class DebugContext implements AutoCloseable { + /** + * The format of the message printed on the console by {@link #getDumpPath} when + * {@link DebugOptions#ShowDumpFiles} is true. The {@code %s} placeholder is replaced with the + * absolute path of the dump file (i.e. the value returned by the method). + */ + public static final String DUMP_FILE_MESSAGE_FORMAT = "Dumping debug output to '%s'"; + + /** + * The regular expression for matching the message derived from + * {@link #DUMP_FILE_MESSAGE_FORMAT}. + * + * Keep in sync with the {@code catch_files} array in {@code common.json}. + */ + public static final String DUMP_FILE_MESSAGE_REGEXP = "Dumping debug output to '(?[^']+)'"; + public static final Description NO_DESCRIPTION = new Description(null, "NO_DESCRIPTION"); public static final GlobalMetrics NO_GLOBAL_METRIC_VALUES = null; public static final Iterable NO_CONFIG_CUSTOMIZERS = Collections.emptyList(); @@ -613,7 +628,7 @@ public String getDumpPath(String extension, boolean createMissingDirectory) { String label = description == null ? null : description.getLabel(); String result = PathUtilities.createUnique(immutable.options, DumpPath, id, label, extension, createMissingDirectory); if (ShowDumpFiles.getValue(immutable.options)) { - TTY.println("Dumping debug output to %s", result); + TTY.println(DUMP_FILE_MESSAGE_FORMAT, result); } return result; } catch (IOException ex) { @@ -1375,6 +1390,30 @@ public void dump(int dumpLevel, Object object, String format, Object arg1, Objec } } + public void dump(int dumpLevel, Object object, String format, Object arg1, Object arg2, Object arg3, Object arg4) { + if (currentScope != null && currentScope.isDumpEnabled(dumpLevel)) { + currentScope.dump(dumpLevel, object, format, arg1, arg2, arg3, arg4); + } + } + + public void dump(int dumpLevel, Object object, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) { + if (currentScope != null && currentScope.isDumpEnabled(dumpLevel)) { + currentScope.dump(dumpLevel, object, format, arg1, arg2, arg3, arg4, arg5); + } + } + + public void dump(int dumpLevel, Object object, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) { + if (currentScope != null && currentScope.isDumpEnabled(dumpLevel)) { + currentScope.dump(dumpLevel, object, format, arg1, arg2, arg3, arg4, arg5, arg6); + } + } + + public void dump(int dumpLevel, Object object, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) { + if (currentScope != null && currentScope.isDumpEnabled(dumpLevel)) { + currentScope.dump(dumpLevel, object, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + } + } + /** * This override exists to catch cases when {@link #dump(int, Object, String, Object)} is called * with one argument bound to a varargs method parameter. It will bind to this method instead of diff --git a/compiler/src/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java b/compiler/src/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java index 69989007bf1d..4e9745250b0c 100644 --- a/compiler/src/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java +++ b/compiler/src/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java @@ -124,7 +124,7 @@ public enum PrintGraphTarget { public static final OptionKey DebugStubsAndSnippets = new OptionKey<>(false); @Option(help = "Send compiler IR to dump handlers on error.", type = OptionType.Debug) public static final OptionKey DumpOnError = new OptionKey<>(false); - @Option(help = "Specify the DumpLevel if CompilationFailureAction#Diagnose is used." + + @Option(help = "Specify the dump level if CompilationFailureAction#Diagnose is used." + "See CompilationFailureAction for details. file:doc-files/CompilationFailureActionHelp.txt", type = OptionType.Debug) public static final OptionKey DiagnoseDumpLevel = new OptionKey<>(DebugContext.VERBOSE_LEVEL); @Option(help = "Disable intercepting exceptions in debug scopes.", type = OptionType.Debug) @@ -196,6 +196,13 @@ protected void onValueUpdate(EconomicMap, Object> values, Boolean o // @formatter:on + /** + * The format of the message printed on the console by {@link #getDumpDirectory} when + * {@link DebugOptions#ShowDumpFiles} is true. The {@code %s} placeholder is replaced with the + * value returned by {@link #getDumpDirectory}. + */ + private static final String DUMP_DIRECTORY_MESSAGE_FORMAT = "Dumping debug output in '%s'"; + /** * Gets the directory in which {@link DebugDumpHandler}s can generate output. This will be the * directory specified by {@link #DumpPath} if it has been set otherwise it will be derived from @@ -214,7 +221,7 @@ public static String getDumpDirectory(OptionValues options) throws IOException { if (!exists(dumpDir)) { createDirectories(dumpDir); if (ShowDumpFiles.getValue(options)) { - TTY.println("Dumping debug output in %s", dumpDir.toString()); + TTY.println(DUMP_DIRECTORY_MESSAGE_FORMAT, dumpDir); } } } diff --git a/compiler/src/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/StandardPathUtilitiesProvider.java b/compiler/src/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/StandardPathUtilitiesProvider.java index 74bfe8f3dd34..d14ff89fbbcf 100644 --- a/compiler/src/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/StandardPathUtilitiesProvider.java +++ b/compiler/src/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/StandardPathUtilitiesProvider.java @@ -52,6 +52,22 @@ * A {@link PathUtilitiesProvider} implemented in terms of {@link File} and {@link Path} APIs. */ public class StandardPathUtilitiesProvider implements PathUtilitiesProvider { + + /** + * The format of the message printed on the console by {@link #archiveAndDelete} showing the + * absolute path of the zip file created. The {@code %s} placeholder is replaced with the + * absolute path of the zip file. + */ + public static final String DIAGNOSTIC_OUTPUT_DIRECTORY_MESSAGE_FORMAT = "Graal diagnostic output saved in '%s'"; + + /** + * The regular expression for matching the message derived from + * {@link #DIAGNOSTIC_OUTPUT_DIRECTORY_MESSAGE_FORMAT}. + * + * Keep in sync with the {@code catch_files} array in {@code common.json}. + */ + public static final String DIAGNOSTIC_OUTPUT_DIRECTORY_MESSAGE_REGEXP = "Graal diagnostic output saved in '(?[^']+)'"; + @Override public String createDirectories(String path) throws IOException { Files.createDirectories(Paths.get(path)); @@ -175,7 +191,7 @@ public FileVisitResult postVisitDirectory(Path d, IOException exc) throws IOExce } }); // Keep this in sync with the catch_files in common.hocon - TTY.println("Graal diagnostic output saved in %s", zipFile); + TTY.println(DIAGNOSTIC_OUTPUT_DIRECTORY_MESSAGE_FORMAT, zipFile); return zipFile.getAbsolutePath(); } catch (IOException e) { toDelete.clear(); diff --git a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Edges.java b/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Edges.java index 19533162e23d..e77fffef5da4 100644 --- a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Edges.java +++ b/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Edges.java @@ -77,6 +77,11 @@ public static NodeList getNodeListUnsafe(Node node, long offset) { return (NodeList) UNSAFE.getObject(node, offset); } + public void putNodeUnsafeChecked(Node node, long offset, Node value, int index) { + verifyUpdateValid(node, index, value); + putNodeUnsafe(node, offset, value); + } + public static void putNodeUnsafe(Node node, long offset, Node value) { UNSAFE.putObject(node, offset, value); } @@ -208,8 +213,7 @@ public void copy(Node fromNode, Node toNode) { * @param value the node to be written to the edge */ public void initializeNode(Node node, int index, Node value) { - verifyUpdateValid(node, index, value); - putNodeUnsafe(node, offsets[index], value); + putNodeUnsafeChecked(node, offsets[index], value, index); } public void initializeList(Node node, int index, NodeList value) { diff --git a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java b/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java index 087d7741281c..bd7c49af43d6 100644 --- a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java +++ b/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java @@ -582,7 +582,11 @@ final void event(NodeEvent e, Node node) { inputChanged(node); break; case ZERO_USAGES: + GraalError.guarantee(node.isAlive(), "must be alive"); usagesDroppedToZero(node); + if (!node.isAlive()) { + throw new GraalError("%s must not kill %s", this, node); + } break; case NODE_ADDED: nodeAdded(node); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK15OrEarlier.java b/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/MemoryKillMarker.java similarity index 73% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK15OrEarlier.java rename to compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/MemoryKillMarker.java index 2967a069bcd6..9f3db2a57b31 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK15OrEarlier.java +++ b/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/MemoryKillMarker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,15 +22,12 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk; +package org.graalvm.compiler.graph; -import java.util.function.BooleanSupplier; - -import org.graalvm.compiler.serviceprovider.JavaVersionUtil; - -public class JDK15OrEarlier implements BooleanSupplier { - @Override - public boolean getAsBoolean() { - return JavaVersionUtil.JAVA_SPEC <= 15; - } +/** + * Any node that includes {@link org.graalvm.compiler.nodeinfo.InputType#Memory InputType.Memory} in + * {@link org.graalvm.compiler.nodeinfo.NodeInfo#allowedUsageTypes() NodeInfo.allowedUsageTypes} + * must also implement a subtype of this interface. + */ +public interface MemoryKillMarker { } diff --git a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java b/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java index b1e358b7a060..5c68673c0d96 100644 --- a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java +++ b/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java @@ -66,12 +66,18 @@ * {@link Graph}. *

* Once a node has been added to a graph, it has a graph-unique {@link #id()}. Edges in the - * subclasses are represented with annotated fields. There are two kind of edges : {@link Input} and - * {@link Successor}. If a field, of a type compatible with {@link Node}, annotated with either - * {@link Input} and {@link Successor} is not null, then there is an edge from this node to the node - * this field points to. + * subclasses are represented with annotated fields. There are two kind of edges: {@link Input} and + * {@link Successor}. If a field of type {@link Node} is annotated with {@link Input} or + * {@link Successor}, it must not be {@code null}. There is an edge from this node to the node + * denoted by the field's value. A field annotated with {@link OptionalInput} is also such an edge + * but it may be {@code null}. *

- * Nodes which are be value numberable should implement the {@link ValueNumberable} interface. + * Exactly one of {@link Input}, {@link OptionalInput}, or {@link Successor} must be applied to all + * fields of a node that are of type {@link Node}. A field of type {@link NodeInputList} must be + * annotated with {@link Input} or {@link OptionalInput}. A field of type {@link NodeSuccessorList} + * must be annotated with {@link Successor}. + *

+ * Nodes which are value numberable should implement the {@link ValueNumberable} interface. * *

Assertions and Verification

* @@ -82,7 +88,7 @@ * only performed if assertions are enabled. */ @NodeInfo -public abstract class Node implements Cloneable, Formattable, NodeInterface { +public abstract class Node implements Cloneable, Formattable { private static final Unsafe UNSAFE = getUnsafe(); @@ -98,10 +104,11 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface { // of this file works around a problem javac has resolving symbols /** - * Denotes a non-optional (non-null) node input. This should be applied to exactly the fields of - * a node that are of type {@link Node} or {@link NodeInputList}. Nodes that update fields of - * type {@link Node} outside of their constructor should call - * {@link Node#updateUsages(Node, Node)} just prior to doing the update of the input. + * Denotes a non-optional (non-null) node input. This should only be applied to fields of type + * {@link Node} or {@link NodeInputList}. + * + * Nodes that update fields of type {@link Node} outside of their constructor should call + * {@link Node#updateUsages(Node, Node)} just prior to the update. */ @java.lang.annotation.Retention(RetentionPolicy.RUNTIME) @java.lang.annotation.Target(ElementType.FIELD) @@ -110,10 +117,11 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface { } /** - * Denotes an optional (nullable) node input. This should be applied to exactly the fields of a - * node that are of type {@link Node} or {@link NodeInputList}. Nodes that update fields of type - * {@link Node} outside of their constructor should call {@link Node#updateUsages(Node, Node)} - * just prior to doing the update of the input. + * Denotes an optional (nullable) node input. This should only be applied to fields of type + * {@link Node} or {@link NodeInputList}. + * + * Nodes that update fields of type {@link Node} outside of their constructor should call + * {@link Node#updateUsages(Node, Node)} just prior to the update. */ @java.lang.annotation.Retention(RetentionPolicy.RUNTIME) @java.lang.annotation.Target(ElementType.FIELD) @@ -121,6 +129,10 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface { InputType value() default InputType.Value; } + /** + * Denotes a non-optional (non-null) node successor. This should only be applied to fields of + * type {@link Node} or {@link NodeSuccessorList}. + */ @java.lang.annotation.Retention(RetentionPolicy.RUNTIME) @java.lang.annotation.Target(ElementType.FIELD) public static @interface Successor { @@ -221,13 +233,20 @@ public interface ValueNumberable { } /** - * Marker interface for nodes that contains other nodes. When the inputs to this node changes, - * users of this node should also be placed on the work list for canonicalization. + * Marker interface for nodes that contain other nodes. When the inputs to {@code this} change, + * users of {@code this} should also be placed on the work list for canonicalization. */ public interface IndirectCanonicalization { } + /** + * The graph owning {@code this}. + */ private Graph graph; + + /** + * @see #id() + */ int id; // this next pointer is used in Graph to implement fast iteration over NodeClass types, it @@ -238,8 +257,13 @@ public interface IndirectCanonicalization { private static final Node[] NO_NODES = {}; /** - * Head of usage list. The elements of the usage list in order are {@link #usage0}, - * {@link #usage1} and {@link #extraUsages}. The first null entry terminates the list. + * Head of usage list (i.e. list of nodes that have {@code this} as an input). Note that each + * element denotes a specific usage so there can be duplicates in the list. For example, a + * {@code ConstNode} modeling a compile constant that is added to itself will show up twice in + * the usage list of the {@code AddNode}. + * + * The elements of the usage list in order are {@link #usage0}, {@link #usage1} and + * {@link #extraUsages}. The first null entry terminates the list. */ Node usage0; Node usage1; @@ -253,11 +277,7 @@ public interface IndirectCanonicalization { public static final int NOT_ITERABLE = -1; static class NodeStackTrace { - final StackTraceElement[] stackTrace; - - NodeStackTrace() { - this.stackTrace = new Throwable().getStackTrace(); - } + final StackTraceElement[] stackTrace = new Throwable().getStackTrace(); private String getString(String label) { StringBuilder sb = new StringBuilder(); @@ -300,31 +320,31 @@ final void init(NodeClass c) { } } + /** + * Gets an identifier for {@code this} that is unique in the context of {@link #graph} iff + * {@code this.graph() != NULL && this.isAlive()}. The value returned by this method can change + * after the graph is {@linkplain Graph#maybeCompress() compressed}. + */ final int id() { return id; } - @Override - public Node asNode() { - return this; - } - /** - * Gets the graph context of this node. + * Gets the graph context of {@code this}. */ public Graph graph() { return graph; } /** - * Gets the option values associated with this node's graph. + * Gets the option values associated with {@code this.graph()}. */ public final OptionValues getOptions() { return graph == null ? null : graph.getOptions(); } /** - * Gets the debug context associated with this node's graph. + * Gets the debug context associated with {@code this.graph()}. */ public final DebugContext getDebug() { return graph.getDebug(); @@ -332,7 +352,7 @@ public final DebugContext getDebug() { /** * Returns an {@link NodeIterable iterable} which can be used to traverse all non-null input - * edges of this node. + * edges of {@code this}. * * @return an {@link NodeIterable iterable} for all non-null input edges. */ @@ -342,7 +362,7 @@ public NodeIterable inputs() { /** * Returns an {@link Iterable iterable} which can be used to traverse all non-null input edges - * of this node. + * of {@code this}. * * @return an {@link Iterable iterable} for all non-null input edges. */ @@ -357,7 +377,7 @@ public abstract static class EdgeVisitor { } /** - * Applies the given visitor to all inputs of this node. + * Applies the given visitor to all inputs of {@code this}. * * @param visitor the visitor to be applied to the inputs */ @@ -366,7 +386,7 @@ public void applyInputs(EdgeVisitor visitor) { } /** - * Applies the given visitor to all successors of this node. + * Applies the given visitor to all successors of {@code this}. * * @param visitor the visitor to be applied to the successors */ @@ -376,7 +396,7 @@ public void applySuccessors(EdgeVisitor visitor) { /** * Returns an {@link NodeIterable iterable} which can be used to traverse all non-null successor - * edges of this node. + * edges of {@code this}. * * @return an {@link NodeIterable iterable} for all non-null successor edges. */ @@ -387,7 +407,7 @@ public NodeIterable successors() { /** * Returns an {@link Iterable iterable} which can be used to traverse all successor edge - * positions of this node. + * positions of {@code this}. * * @return an {@link Iterable iterable} for all successor edge positoins. */ @@ -396,7 +416,7 @@ public Iterable successorPositions() { } /** - * Gets the maximum number of usages this node has had at any point in time. + * Gets the maximum number of usages {@code this} has had at any point in time. */ public int getUsageCount() { if (usage0 == null) { @@ -409,50 +429,50 @@ public int getUsageCount() { } /** - * Gets the list of nodes that use this node (i.e., as an input). + * Gets the list of nodes that use {@code this} (i.e., as an input). */ public final NodeIterable usages() { return new NodeUsageIterable(this); } /** - * Checks whether this node has no usages. + * Checks whether {@code this} has no usages. */ public final boolean hasNoUsages() { return this.usage0 == null; } /** - * Checks whether this node has usages. + * Checks whether {@code this} has usages. */ public final boolean hasUsages() { return this.usage0 != null; } /** - * Checks whether this node has more than one usages. + * Checks whether {@code this} has more than one usage. */ public final boolean hasMoreThanOneUsage() { return this.usage1 != null; } /** - * Checks whether this node has exactly one usage. + * Checks whether {@code this} has exactly one usage. */ public final boolean hasExactlyOneUsage() { return hasUsages() && !hasMoreThanOneUsage(); } /** - * Checks whether this node has only usages of that type. + * Checks whether {@code this} has only usages of type {@code inputType}. * - * @param type the type of usages to look for + * @param inputType the type of usages to look for */ - public final boolean hasOnlyUsagesOfType(InputType type) { + public final boolean hasOnlyUsagesOfType(InputType inputType) { for (Node usage : usages()) { for (Position pos : usage.inputPositions()) { if (pos.get(usage) == this) { - if (pos.getInputType() != type) { + if (pos.getInputType() != inputType) { return false; } } @@ -461,6 +481,24 @@ public final boolean hasOnlyUsagesOfType(InputType type) { return true; } + /** + * Checks whether this node has usages of a given {@link InputType}. + * + * @param type the type of usages to look for + */ + public final boolean hasUsagesOfType(InputType type) { + for (Node usage : usages()) { + for (Position pos : usage.inputPositions()) { + if (pos.get(usage) == this) { + if (pos.getInputType() == type) { + return true; + } + } + } + } + return false; + } + /** * Adds a given node to this node's {@linkplain #usages() usages}. * @@ -528,7 +566,7 @@ private void movUsageFromEndToIndexOne() { } /** - * Removes a given node from this node's {@linkplain #usages() usages}. + * Removes one occurrence of a given node from this node's {@linkplain #usages() usages}. * * @param node the node to remove * @return whether or not {@code usage} was in the usage list @@ -599,16 +637,15 @@ public final boolean isUnregistered() { } /** - * Updates the usages sets of the given nodes after an input slot is changed from - * {@code oldInput} to {@code newInput} by removing this node from {@code oldInput}'s usages and - * adds this node to {@code newInput}'s usages. + * Removes one occurrence of {@code this} from {@code oldInput}'s usages and adds it to + * {@code newInput}'s usages. */ protected void updateUsages(Node oldInput, Node newInput) { assert isAlive() && (newInput == null || newInput.isAlive()) : "adding " + newInput + " to " + this + " instead of " + oldInput; if (oldInput != newInput) { if (oldInput != null) { boolean result = removeThisFromUsages(oldInput); - assert assertTrue(result, "not found in usages, old input: %s", oldInput); + assertTrue(result, "not found in usages, old input: %s", oldInput); } maybeNotifyInputChanged(this); if (newInput != null) { @@ -620,33 +657,30 @@ protected void updateUsages(Node oldInput, Node newInput) { } } - protected void updateUsagesInterface(NodeInterface oldInput, NodeInterface newInput) { - updateUsages(oldInput == null ? null : oldInput.asNode(), newInput == null ? null : newInput.asNode()); - } - /** * Updates the predecessor of the given nodes after a successor slot is changed from - * oldSuccessor to newSuccessor: removes this node from oldSuccessor's predecessors and adds - * this node to newSuccessor's predecessors. + * oldSuccessor to newSuccessor: removes {@code this} from oldSuccessor's predecessors and adds + * {@code this} to newSuccessor's predecessors. */ protected void updatePredecessor(Node oldSuccessor, Node newSuccessor) { - assert isAlive() && (newSuccessor == null || newSuccessor.isAlive()) || newSuccessor == null && !isAlive() : "adding " + newSuccessor + " to " + this + " instead of " + oldSuccessor; + assertTrue(isAlive() && (newSuccessor == null || newSuccessor.isAlive()) || newSuccessor == null && !isAlive(), "adding %s to %s instead of %s", newSuccessor, this, oldSuccessor); assert graph == null || !graph.isFrozen(); if (oldSuccessor != newSuccessor) { if (oldSuccessor != null) { - assert assertTrue(newSuccessor == null || oldSuccessor.predecessor == this, "wrong predecessor in old successor (%s): %s, should be %s", oldSuccessor, oldSuccessor.predecessor, this); + assertTrue(newSuccessor == null || oldSuccessor.predecessor == this, "wrong predecessor in old successor (%s): %s, should be %s", oldSuccessor, oldSuccessor.predecessor, this); oldSuccessor.predecessor = null; } if (newSuccessor != null) { - assert assertTrue(newSuccessor.predecessor == null, "unexpected non-null predecessor in new successor (%s): %s, this=%s", newSuccessor, newSuccessor.predecessor, this); + assertTrue(newSuccessor.predecessor == null, "unexpected non-null predecessor in new successor (%s): %s, this=%s", newSuccessor, newSuccessor.predecessor, this); newSuccessor.predecessor = this; + maybeNotifyInputChanged(newSuccessor); } maybeNotifyInputChanged(this); } } void initialize(Graph newGraph) { - assert assertTrue(id == INITIAL_ID, "unexpected id: %d", id); + assertTrue(id == INITIAL_ID, "unexpected id: %d", id); this.graph = newGraph; newGraph.register(this); NodeClass nc = nodeClass; @@ -655,7 +689,7 @@ void initialize(Graph newGraph) { } /** - * Information associated with this node. A single value is stored directly in the field. + * Information associated with {@code this}. A single value is stored directly in the field. * Multiple values are stored by creating an Object[]. */ private Object annotation; @@ -701,9 +735,8 @@ private void setNodeInfo(Class clazz, T value) { } /** - * Gets the source position information for this node or null if it doesn't exist. + * Gets the source position information for {@code this} or null if it doesn't exist. */ - public NodeSourcePosition getNodeSourcePosition() { return getNodeInfo(NodeSourcePosition.class); } @@ -763,60 +796,137 @@ public boolean isAllowedUsageType(InputType type) { return getNodeClass().getAllowedUsageTypes().contains(type); } - private boolean checkReplaceWith(Node other) { + private boolean checkReplaceWith(Node replacement) { if (graph != null && graph.isFrozen()) { fail("cannot modify frozen graph"); } - if (other == this) { + if (replacement == this) { fail("cannot replace a node with itself"); } if (isDeleted()) { fail("cannot replace deleted node"); } - if (other != null && other.isDeleted()) { - fail("cannot replace with deleted node %s", other); + if (replacement != null && replacement.isDeleted()) { + fail("cannot replace with deleted node %s", replacement); } return true; } - public final void replaceAtUsages(Node other) { - replaceAtAllUsages(other, (Node) null); + /** + * For each use of {@code this} in another node, replace it with {@code replacement}. + * + * This is shown by the graph transformation below where edges are from usages to inputs (e.g. + * {@code this} is an input of {@code n0}). + * + * Before: + * + *
+     *       this
+     *         ^
+     *         |
+     *        /|\
+     *       / | \
+     *      /  |  \
+     *    n0  n1 ..nN
+     *
+     * 
+ * + * After: + * + *
+     *     replacement
+     *         ^
+     *         |
+     *        /|\
+     *       / | \
+     *      /  |  \
+     *    n0  n1 ..nN
+     * 
+ * + * If {@code replacement == null}, then the edges are simply removed. + */ + public final void replaceAtUsages(Node replacement) { + replaceAtAllUsages(replacement, false); } - public final void replaceAtUsages(Node other, Predicate filter) { - replaceAtUsages(other, filter, null); + /** + * For each use of {@code this} in another node, {@code n}, replace it with {@code replacement} + * if {@code filter == null} or {@code filter.test(n) == true}. + * + * @see #replaceAtUsages(Node) + */ + public final void replaceAtUsages(Node replacement, Predicate filter) { + replaceAtUsages(replacement, filter, false); } - public final void replaceAtUsagesAndDelete(Node other) { - replaceAtUsages(other, null, this); + /** + * For each use of {@code this} in another node, replace it with {@code replacement} and then + * {@linkplain #safeDelete() remove} {@code this} from the graph. + * + * @see #replaceAtUsages(Node) + */ + public final void replaceAtUsagesAndDelete(Node replacement) { + replaceAtUsages(replacement, null, true); safeDelete(); } - public final void replaceAtUsagesAndDelete(Node other, Predicate filter) { - replaceAtUsages(other, filter, this); + /** + * For each use of {@code this} in another node, {@code n}, replace it with {@code replacement} + * if {@code filter == null} or {@code filter.test(n) == true} and then + * {@linkplain #safeDelete() remove} {@code this} from the graph. + * + * @see #replaceAtUsages(Node) + */ + public final void replaceAtUsagesAndDelete(Node replacement, Predicate filter) { + replaceAtUsages(replacement, filter, true); safeDelete(); } - protected void replaceAtUsages(Node other, Predicate filter, Node toBeDeleted) { + /** + * For each use of {@code this} in another node, {@code n}, replace it with {@code replacement} + * if {@code filter == null} or {@code filter.test(n) == true}. + * + * @param forDeletion specifies if the caller will {@linkplain #safeDelete() remove} + * {@code this} from the graph after this method returns + * @see #replaceAtUsages(Node) + */ + private void replaceAtUsages(Node replacement, Predicate filter, boolean forDeletion) { if (filter == null) { - replaceAtAllUsages(other, toBeDeleted); + replaceAtAllUsages(replacement, forDeletion); } else { - replaceAtMatchingUsages(other, filter, toBeDeleted); + replaceAtMatchingUsages(replacement, filter, forDeletion); } + assert checkReplaceAtUsagesInvariants(replacement); + } + + /** + * Subclasses can override this to check invariants related to replacing uses of {@code this}. + * + * @param replacement + * @return {@code true} if all invariants hold + */ + protected boolean checkReplaceAtUsagesInvariants(Node replacement) { + return true; } - protected void replaceAtAllUsages(Node other, Node toBeDeleted) { - checkReplaceWith(other); + /** + * For each use of {@code this} in another node, replace it with {@code replacement}. + * + * @param forDeletion specifies if the caller will {@linkplain #safeDelete() remove} + * {@code this} from the graph after this method returns + */ + public final void replaceAtAllUsages(Node replacement, boolean forDeletion) { + checkReplaceWith(replacement); if (usage0 == null) { return; } - replaceAtUsage(other, toBeDeleted, usage0); + replaceAtUsage(replacement, forDeletion, usage0); usage0 = null; if (usage1 == null) { return; } - replaceAtUsage(other, toBeDeleted, usage1); + replaceAtUsage(replacement, forDeletion, usage1); usage1 = null; if (extraUsagesCount <= 0) { @@ -824,37 +934,53 @@ protected void replaceAtAllUsages(Node other, Node toBeDeleted) { } for (int i = 0; i < extraUsagesCount; i++) { Node usage = extraUsages[i]; - replaceAtUsage(other, toBeDeleted, usage); + replaceAtUsage(replacement, forDeletion, usage); } this.extraUsages = NO_NODES; this.extraUsagesCount = 0; } - private void replaceAtUsage(Node other, Node toBeDeleted, Node usage) { - boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other); - assert assertTrue(result, "not found in inputs, usage: %s", usage); + /** + * For the use of {@code this} in another node represented by {@code usage}, replace it with + * {@code replacement}. + * + * @param forDeletion specifies if the caller will {@linkplain #safeDelete() remove} + * {@code this} from the graph after this method returns + * + * @see #replaceAtUsages(Node) + */ + private void replaceAtUsage(Node replacement, boolean forDeletion, Node usage) { + boolean result = usage.getNodeClass().replaceFirstInput(usage, this, replacement); + assertTrue(result, "not found in inputs, usage: %s", usage); /* * Don't notify for nodes which are about to be deleted. */ - if (toBeDeleted == null || usage != toBeDeleted) { + if (!forDeletion || usage != this) { maybeNotifyInputChanged(usage); } - if (other != null) { - other.addUsage(usage); + if (replacement != null) { + replacement.addUsage(usage); } } - private void replaceAtMatchingUsages(Node other, Predicate filter, Node toBeDeleted) { - if (filter == null) { - throw fail("filter cannot be null"); - } - checkReplaceWith(other); + /** + * For each use of {@code this} in another node, {@code n}, replace it with {@code replacement} + * if {@code filter.test(n) == true}. + * + * @param forDeletion specifies if the caller will {@linkplain #safeDelete() remove} + * {@code this} from the graph after this method returns + * + * @see #replaceAtUsages(Node) + */ + private void replaceAtMatchingUsages(Node replacement, Predicate filter, boolean forDeletion) { + Objects.requireNonNull(filter); + checkReplaceWith(replacement); int i = 0; int usageCount = this.getUsageCount(); while (i < usageCount) { Node usage = this.getUsageAt(i); if (filter.test(usage)) { - replaceAtUsage(other, toBeDeleted, usage); + replaceAtUsage(replacement, forDeletion, usage); this.movUsageFromEndTo(i); usageCount--; } else { @@ -878,21 +1004,33 @@ public Node singleUsage() { return this.usage0; } - public void replaceAtMatchingUsages(Node other, NodePredicate usagePredicate) { - checkReplaceWith(other); - replaceAtMatchingUsages(other, usagePredicate, null); + /** + * For each use of {@code this} in another node, {@code n}, replace it with {@code replacement} + * if {@code filter.test(n) == true}. + * + * @see #replaceAtUsages(Node) + */ + public void replaceAtMatchingUsages(Node replacement, NodePredicate usagePredicate) { + checkReplaceWith(replacement); + replaceAtMatchingUsages(replacement, usagePredicate, false); } - private void replaceAtUsagePos(Node other, Node usage, Position pos) { - pos.initialize(usage, other); + private void replaceAtUsagePos(Node replacement, Node usage, Position pos) { + pos.initialize(usage, replacement); maybeNotifyInputChanged(usage); - if (other != null) { - other.addUsage(usage); + if (replacement != null) { + replacement.addUsage(usage); } } - public void replaceAtUsages(Node other, InputType type) { - checkReplaceWith(other); + /** + * For each use of {@code this} in another node, {@code n}, replace it with {@code replacement} + * if the type of the use is {@code inputType}. + * + * @see #replaceAtUsages(Node) + */ + public void replaceAtUsages(Node replacement, InputType inputType) { + checkReplaceWith(replacement); int i = 0; int usageCount = this.getUsageCount(); if (usageCount == 0) { @@ -901,8 +1039,8 @@ public void replaceAtUsages(Node other, InputType type) { usages: while (i < usageCount) { Node usage = this.getUsageAt(i); for (Position pos : usage.inputPositions()) { - if (pos.getInputType() == type && pos.get(usage) == this) { - replaceAtUsagePos(other, usage, pos); + if (pos.getInputType() == inputType && pos.get(usage) == this) { + replaceAtUsagePos(replacement, usage, pos); this.movUsageFromEndTo(i); usageCount--; continue usages; @@ -915,8 +1053,14 @@ public void replaceAtUsages(Node other, InputType type) { } } - public void replaceAtUsages(Node other, InputType... inputTypes) { - checkReplaceWith(other); + /** + * For each use of {@code this} in another node, {@code n}, replace it with {@code replacement} + * if the type of the use is in {@code inputTypes}. + * + * @see #replaceAtUsages(Node) + */ + public void replaceAtUsages(Node replacement, InputType... inputTypes) { + checkReplaceWith(replacement); int i = 0; int usageCount = this.getUsageCount(); if (usageCount == 0) { @@ -927,7 +1071,7 @@ public void replaceAtUsages(Node other, InputType... inputTypes) { for (Position pos : usage.inputPositions()) { for (InputType type : inputTypes) { if (pos.getInputType() == type && pos.get(usage) == this) { - replaceAtUsagePos(other, usage, pos); + replaceAtUsagePos(replacement, usage, pos); this.movUsageFromEndTo(i); usageCount--; continue usages; @@ -951,66 +1095,134 @@ private void maybeNotifyInputChanged(Node node) { } } + /** + * Iterates over each {@link NodeEventListener} attached to {@code this.graph()} if + * {@code node.isAlive()} and notifies the listener that {@code node} has had its last usage + * removed. + */ public void maybeNotifyZeroUsages(Node node) { - if (graph != null) { + if (graph != null && node.isAlive()) { assert !graph.isFrozen(); NodeEventListener listener = graph.nodeEventListener; - if (listener != null && node.isAlive()) { + if (listener != null) { listener.event(Graph.NodeEvent.ZERO_USAGES, node); } } } - public void replaceAtPredecessor(Node other) { - checkReplaceWith(other); + /** + * Updates the control flow edge, if it exists, from {@link #predecessor()} to {@code this} to + * have a target of {@code replacement}. + */ + public void replaceAtPredecessor(Node replacement) { + checkReplaceWith(replacement); if (predecessor != null) { - if (!predecessor.getNodeClass().replaceFirstSuccessor(predecessor, this, other)) { + if (!predecessor.getNodeClass().replaceFirstSuccessor(predecessor, this, replacement)) { fail("not found in successors, predecessor: %s", predecessor); } - predecessor.updatePredecessor(this, other); + predecessor.updatePredecessor(this, replacement); } } - public void replaceAndDelete(Node other) { - checkReplaceWith(other); - if (other == null) { + /** + * Replaces {@code this} at its predecessor (if any) and its usages with {@code replacement} and + * removes it from its graph. + */ + public void replaceAndDelete(Node replacement) { + checkReplaceWith(replacement); + if (replacement == null) { fail("cannot replace with null"); } if (this.hasUsages()) { - replaceAtUsages(other); + replaceAtUsages(replacement); } - replaceAtPredecessor(other); + replaceAtPredecessor(replacement); this.safeDelete(); } + /** + * Finds the first {@link Successor} in {@code this} whose value is {@code oldSuccessor} and + * replaces it with {@code newSuccessor}. The predecessor fields in {@code oldSuccessor} and + * {@code newSuccessor} are updated to reflect any change made. + */ public void replaceFirstSuccessor(Node oldSuccessor, Node newSuccessor) { if (nodeClass.replaceFirstSuccessor(this, oldSuccessor, newSuccessor)) { updatePredecessor(oldSuccessor, newSuccessor); } } + /** + * Finds the first {@link Input} or {@link OptionalInput} in {@code this} whose value is + * {@code oldInput} and replaces it with {@code newInput}. If the input is changed, the usage + * info for {@code oldInput} and {@code newInput} is updated as well. + * + * Before {@code this.replaceFirstInput(n0, n2)}: + * + *
+     *       n0  n1  n0
+     *        \  |  /
+     *         \ | /
+     *          \|/
+     *           |
+     *           V
+     *         this
+     * 
+ * + * After {@code this.replaceFirstInput(n0, n2)}: + * + *
+     *       n2  n1  n0
+     *        \  |  /
+     *         \ | /
+     *          \|/
+     *           |
+     *           V
+     *         this
+     * 
+ */ public void replaceFirstInput(Node oldInput, Node newInput) { if (nodeClass.replaceFirstInput(this, oldInput, newInput)) { updateUsages(oldInput, newInput); } } + /** + * Finds all {@link Input}s and {@link OptionalInput}s in {@code this} whose value is + * {@code oldInput} and replaces them with {@code newInput}. If any input is changed, the usage + * info for {@code oldInput} and {@code newInput} is updated as well. + * + * Before {@code this.replaceAllInputs(n0, n2)}: + * + *
+     *       n0  n1  n0
+     *        \  |  /
+     *         \ | /
+     *          \|/
+     *           |
+     *           V
+     *         this
+     * 
+ * + * After {@code this.replaceAllInputs(n0, n2)}: + * + *
+     *       n2  n1  n2
+     *        \  |  /
+     *         \ | /
+     *          \|/
+     *           |
+     *           V
+     *         this
+     * 
+ */ public void replaceAllInputs(Node oldInput, Node newInput) { while (nodeClass.replaceFirstInput(this, oldInput, newInput)) { updateUsages(oldInput, newInput); } } - public void replaceFirstInput(Node oldInput, Node newInput, InputType type) { - for (Position pos : inputPositions()) { - if (pos.getInputType() == type && pos.get(this) == oldInput) { - pos.set(this, newInput); - } - } - } - public void clearInputs() { - assert assertFalse(isDeleted(), "cannot clear inputs of deleted node"); + assertFalse(isDeleted(), "cannot clear inputs of deleted node"); getNodeClass().unregisterAtInputsAsUsage(this); } @@ -1019,7 +1231,7 @@ boolean removeThisFromUsages(Node n) { } public void clearSuccessors() { - assert assertFalse(isDeleted(), "cannot clear successors of deleted node"); + assertFalse(isDeleted(), "cannot clear successors of deleted node"); getNodeClass().unregisterAtSuccessorsAsPredecessor(this); } @@ -1031,8 +1243,8 @@ private boolean checkDeletion() { } /** - * Removes this node from its graph. This node must have no {@linkplain Node#usages() usages} - * and no {@linkplain #predecessor() predecessor}. + * Removes {@code this} from {@code this.graph()}. This node must have no + * {@linkplain Node#usages() usages} and no {@linkplain #predecessor() predecessor}. */ public void safeDelete() { assert checkDeletion(); @@ -1062,8 +1274,8 @@ public final Node copyWithInputs(boolean insertIntoGraph) { } /** - * @param newNode the result of cloning this node or {@link Unsafe#allocateInstance(Class) raw - * allocating} a copy of this node + * @param newNode the result of cloning {@code this} or {@link Unsafe#allocateInstance(Class) + * raw allocating} a copy of {@code this} * @param type the type of edges to process * @param edgesToCopy if {@code type} is in this set, the edges are copied otherwise they are * cleared @@ -1083,14 +1295,14 @@ private void copyOrClearEdgesForClone(Node newNode, Edges.Type type, EnumSet WithOnlySucessorEdges = EnumSet.of(Successors); /** - * Makes a copy of this node in(to) a given graph. + * Makes a copy of {@code this} in(to) a given graph. * - * @param into the graph in which the copy will be registered (which may be this node's graph) - * or null if the copy should not be registered in a graph + * @param into the graph in which the copy will be registered (which may be + * {@code this.graph()}) or null if the copy should not be registered in a graph * @param edgesToCopy specifies the edges to be copied. The edges not specified in this set are * initialized to their default value (i.e., {@code null} for a direct edge, an empty * list for an edge list) - * @return the copy of this node + * @return the copy of {@code this} */ final Node clone(Graph into, EnumSet edgesToCopy) { final NodeClass nodeClassTmp = getNodeClass(); @@ -1218,8 +1430,8 @@ public boolean assertFalse(boolean condition, String message, Object... args) { } } - protected VerificationError fail(String message, Object... args) throws GraalGraphError { - throw new VerificationError(message, args).addContext(this); + protected GraalGraphError fail(String message, Object... args) throws GraalGraphError { + throw new GraalGraphError(message, args).addContext(this); } public Iterable cfgPredecessors() { @@ -1231,9 +1443,9 @@ public Iterable cfgPredecessors() { } /** - * Returns an iterator that will provide all control-flow successors of this node. Normally this - * will be the contents of all fields annotated with {@link Successor}, but some node classes - * (like EndNode) may return different nodes. + * Returns an iterator that will provide all control-flow successors of {@code this}. Normally + * this will be the contents of all fields annotated with {@link Successor}, but some node + * classes (like EndNode) may return different nodes. */ public Iterable cfgSuccessors() { return successors(); @@ -1259,16 +1471,16 @@ public final int hashCode() { */ /** - * Provides a {@link Map} of properties of this node for use in debugging (e.g., to view in the - * ideal graph visualizer). + * Provides a {@link Map} of properties of {@code this} for use in debugging (e.g., to view in + * the ideal graph visualizer). */ public final Map getDebugProperties() { return getDebugProperties(new HashMap<>()); } /** - * Fills a {@link Map} with properties of this node for use in debugging (e.g., to view in the - * ideal graph visualizer). Subclasses overriding this method should also fill the map using + * Fills a {@link Map} with properties of {@code this} for use in debugging (e.g., to view in + * the ideal graph visualizer). Subclasses overriding this method should also fill the map using * their superclass. * * @param map @@ -1302,7 +1514,7 @@ public final String toString() { } /** - * Creates a String representation for this node with a given {@link Verbosity}. + * Creates a String representation for {@code this} with a given {@link Verbosity}. */ public String toString(Verbosity verbosity) { switch (verbosity) { @@ -1400,7 +1612,7 @@ public void formatTo(Formatter formatter, int flags, int width, int precision) { * * The result of this method undefined if {@code other.getClass() != this.getClass()}. * - * @param other a node of exactly the same type as this node + * @param other a node of exactly the same type as {@code this} * @return true if the data fields of this object and {@code other} are equal */ public final boolean valueEquals(Node other) { @@ -1408,7 +1620,7 @@ public final boolean valueEquals(Node other) { } /** - * Determines if this node is equal to the other node while ignoring differences in + * Determines if {@code this} is equal to the other node while ignoring differences in * {@linkplain Successor control-flow} edges. * */ diff --git a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java b/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java index 74ae7c4b5751..41c0ed9b30bd 100644 --- a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java +++ b/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java @@ -222,6 +222,8 @@ public NodeClass(Class clazz, NodeClass superNodeClass, FieldsScan try (DebugCloseable t1 = Init_AllowedUsages.start(debug)) { allowedUsageTypes = superNodeClass == null ? EnumSet.noneOf(InputType.class) : superNodeClass.allowedUsageTypes.clone(); allowedUsageTypes.addAll(Arrays.asList(info.allowedUsageTypes())); + GraalError.guarantee(!allowedUsageTypes.contains(InputType.Memory) || MemoryKillMarker.class.isAssignableFrom(clazz), + "Node of type %s with allowedUsageType of memory must inherit from MemoryKill", clazz); } if (presetIterableIds != null) { @@ -503,6 +505,8 @@ protected void scanField(Field field, long offset) { } else { inputType = optionalInputAnnotation.value(); } + GraalError.guarantee(inputType != InputType.Memory || MemoryKillMarker.class.isAssignableFrom(type) || NodeInputList.class.isAssignableFrom(type), + "field type of input annotated with Memory must inherit from MemoryKill: %s", field); inputs.add(new InputInfo(offset, field.getName(), type, field.getDeclaringClass(), inputType, field.isAnnotationPresent(Node.OptionalInput.class))); } else if (successorAnnotation != null) { if (SUCCESSOR_LIST_CLASS.isAssignableFrom(type)) { @@ -1250,14 +1254,15 @@ private static void pushAllHelper(NodeStack stack, Node node, long offset) { } public void applySuccessors(Node node, EdgeVisitor consumer) { - applyEdges(node, consumer, this.successorIteration); + applyEdges(node, consumer, this.successorIteration, successors); } public void applyInputs(Node node, EdgeVisitor consumer) { - applyEdges(node, consumer, this.inputsIteration); + applyEdges(node, consumer, this.inputsIteration, inputs); } - private static void applyEdges(Node node, EdgeVisitor consumer, long mask) { + private static void applyEdges(Node node, EdgeVisitor consumer, long mask, Edges edges) { + int index = 0; long myMask = mask; while (myMask != 0) { long offset = (myMask & OFFSET_MASK); @@ -1266,13 +1271,14 @@ private static void applyEdges(Node node, EdgeVisitor consumer, long mask) { if (curNode != null) { Node newNode = consumer.apply(node, curNode); if (newNode != curNode) { - Edges.putNodeUnsafe(node, offset, newNode); + edges.putNodeUnsafeChecked(node, offset, newNode, index); } } } else { applyHelper(node, consumer, offset); } myMask >>>= NEXT_EDGE; + index++; } } @@ -1351,22 +1357,41 @@ private static void registerAtSuccessorsAsPredecessorHelper(Node node, long offs } } + /** + * Finds the first {@link Input} or {@link OptionalInput} in {@code node} whose value + * {@code == key} and replaces it with {@code replacement}. + * + * Pre-requisite: {@code node.getNodeClass() == this} + * + * @return {@code true} if a replacement was made, {@code false} if {@code key} was not an input + */ public boolean replaceFirstInput(Node node, Node key, Node replacement) { - return replaceFirstEdge(node, key, replacement, this.inputsIteration); + assert node.getNodeClass() == this; + return replaceFirstEdge(node, key, replacement, this.inputsIteration, inputs); } + /** + * Finds the first {@link Successor} in {@code node} whose value is {@code key} and replaces it + * with {@code replacement}. + * + * Pre-requisite: {@code node.getNodeClass() == this} + * + * @return {@code true} if a replacement was made, {@code false} if {@code key} was not an input + */ public boolean replaceFirstSuccessor(Node node, Node key, Node replacement) { - return replaceFirstEdge(node, key, replacement, this.successorIteration); + assert node.getNodeClass() == this; + return replaceFirstEdge(node, key, replacement, this.successorIteration, successors); } - public static boolean replaceFirstEdge(Node node, Node key, Node replacement, long mask) { + private static boolean replaceFirstEdge(Node node, Node key, Node replacement, long mask, Edges edges) { + int index = 0; long myMask = mask; while (myMask != 0) { long offset = (myMask & OFFSET_MASK); if ((myMask & LIST_MASK) == 0) { Object curNode = Edges.getNodeUnsafe(node, offset); if (curNode == key) { - Edges.putNodeUnsafe(node, offset, replacement); + edges.putNodeUnsafeChecked(node, offset, replacement, index); return true; } } else { @@ -1376,11 +1401,12 @@ public static boolean replaceFirstEdge(Node node, Node key, Node replacement, lo } } myMask >>>= NEXT_EDGE; + index++; } return false; } - public void registerAtInputsAsUsage(Node node) { + void registerAtInputsAsUsage(Node node) { long myMask = this.inputsIteration; while (myMask != 0) { long offset = (myMask & OFFSET_MASK); diff --git a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeIdAccessor.java b/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeIdAccessor.java index 4e1a0c1bc037..6debde470cee 100644 --- a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeIdAccessor.java +++ b/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeIdAccessor.java @@ -44,12 +44,12 @@ Graph getGraph() { * Verifies that node identifiers have not changed since this object was created. * * @return true if the check succeeds - * @throws VerificationError if the check fails + * @throws GraalGraphError if the check fails */ boolean verifyIdsAreStable() { int compressions = graph.compressions - epoch; if (compressions != 0) { - throw new VerificationError("accessing node id in %s across %d graph compression%s", graph, compressions, compressions == 1 ? "" : "s"); + throw new GraalGraphError("accessing node id in %s across %d graph compression%s", graph, compressions, compressions == 1 ? "" : "s"); } return true; } diff --git a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeInputList.java b/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeInputList.java index bcad5f13e615..55ec72e6e3a3 100644 --- a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeInputList.java +++ b/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeInputList.java @@ -26,7 +26,6 @@ import static org.graalvm.compiler.graph.Edges.Type.Inputs; -import java.util.Collection; import java.util.List; import org.graalvm.compiler.graph.Edges.Type; @@ -51,11 +50,6 @@ public NodeInputList(Node self, List elements) { assert self.hasNoUsages(); } - public NodeInputList(Node self, Collection elements) { - super(self, elements); - assert self.hasNoUsages(); - } - @Override protected void update(T oldNode, T newNode) { self.updateUsages(oldNode, newNode); diff --git a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeList.java b/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeList.java index 05911e41673b..01d7fab4ee2c 100644 --- a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeList.java +++ b/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeList.java @@ -110,27 +110,6 @@ private static void checkMaxSize(int value) { } } - protected NodeList(Node self, Collection elements) { - this.self = self; - if (elements == null || elements.isEmpty()) { - this.size = 0; - this.nodes = EMPTY_NODE_ARRAY; - this.initialSize = 0; - } else { - int newSize = elements.size(); - checkMaxSize(newSize); - this.size = newSize; - this.initialSize = newSize; - this.nodes = new Node[elements.size()]; - int i = 0; - for (NodeInterface n : elements) { - this.nodes[i] = n.asNode(); - assert this.nodes[i] == null || !this.nodes[i].isDeleted(); - i++; - } - } - } - /** * Removes {@code null} values from the list. */ diff --git a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeMap.java b/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeMap.java index 30fbeaa25faa..ff89647d8c27 100644 --- a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeMap.java +++ b/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeMap.java @@ -96,7 +96,7 @@ public Graph graph() { public void set(Node node, T value) { assert check(node); if (!node.isAlive()) { - throw new VerificationError("this node is not alive: " + node); + throw new GraalGraphError("this node is not alive: " + node); } values[getNodeId(node)] = value; } diff --git a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/VerificationError.java b/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/VerificationError.java deleted file mode 100644 index b41d795d4ad0..000000000000 --- a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/VerificationError.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.graph; - -/** - * This error represents a failed verification of a node . It must only be used for conditions that - * should never occur during normal operation. - */ -public class VerificationError extends GraalGraphError { - - private static final long serialVersionUID = 8459607567446819822L; - - /** - * This constructor creates a {@link VerificationError} with a message assembled via - * {@link String#format(String, Object...)}. It always uses the ENGLISH locale in order to - * always generate the same output. - * - * @param msg the message that will be associated with the error, in String.format syntax - * @param args parameters to String.format - parameters that implement {@link Iterable} will be - * expanded into a [x, x, ...] representation. - */ - public VerificationError(String msg, Object... args) { - super(msg, args); - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java index ce6b98a1f7c5..133ddbf5fd1e 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java +++ b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java @@ -32,7 +32,6 @@ import static jdk.vm.ci.code.ValueUtil.asRegister; import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp; import static org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode.IMMEDIATE_UNSIGNED_SCALED; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry; import org.graalvm.compiler.asm.Assembler; @@ -44,7 +43,6 @@ import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.ScratchRegister; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.aarch64.AArch64NodeMatchRules; -import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; import org.graalvm.compiler.core.gen.LIRGenerationProvider; @@ -55,7 +53,6 @@ import org.graalvm.compiler.hotspot.HotSpotHostBackend; import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult; import org.graalvm.compiler.hotspot.HotSpotMarkId; -import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; import org.graalvm.compiler.hotspot.stubs.Stub; @@ -83,7 +80,6 @@ import jdk.vm.ci.code.RegisterConfig; import jdk.vm.ci.code.StackSlot; import jdk.vm.ci.hotspot.HotSpotCallingConventionType; -import jdk.vm.ci.hotspot.HotSpotSentinelConstant; import jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -136,8 +132,7 @@ public InstalledCode createInstalledCode(DebugContext debug, boolean isDefault, Object[] context) { boolean isStub = (method == null); - boolean isAOT = compilationResult.isImmutablePIC(); - if (!isStub && !isAOT) { + if (!isStub) { // Non-stub compilation results are installed into HotSpot as nmethods. As AArch64 has // a constraint that the instruction at nmethod verified entry point should be a nop or // jump, AArch64HotSpotBackend always generate a nop placeholder before the code body @@ -336,7 +331,7 @@ private void emitCodePrefix(CompilationResultBuilder crb, ResolvedJavaMethod ins Register klass = r10; if (config.useCompressedClassPointers) { masm.ldr(32, klass, klassAddress); - AArch64HotSpotMove.decodeKlassPointer(crb, masm, klass, klass, config.getKlassEncoding()); + AArch64HotSpotMove.decodeKlassPointer(masm, klass, klass, config.getKlassEncoding()); } else { masm.ldr(64, klass, klassAddress); } @@ -351,23 +346,6 @@ private void emitCodePrefix(CompilationResultBuilder crb, ResolvedJavaMethod ins masm.align(config.codeEntryAlignment); masm.bind(verifiedStub); crb.recordMark(crb.compilationResult.getEntryBCI() != -1 ? HotSpotMarkId.OSR_ENTRY : HotSpotMarkId.VERIFIED_ENTRY); - - if (GeneratePIC.getValue(crb.getOptions())) { - // Check for method state - HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; - if (!frameContext.isStub) { - crb.recordInlineDataInCodeWithNote(new HotSpotSentinelConstant(LIRKind.value(AArch64Kind.QWORD), JavaKind.Long), HotSpotConstantLoadAction.MAKE_NOT_ENTRANT); - try (ScratchRegister sc = masm.getScratchRegister()) { - Register scratch = sc.getRegister(); - masm.adrpAdd(scratch); - masm.ldr(64, scratch, AArch64Address.createBaseRegisterOnlyAddress(64, scratch)); - Label noCall = new Label(); - masm.cbz(64, scratch, noCall); - AArch64Call.directJmp(crb, masm, getForeignCalls().lookupForeignCall(WRONG_METHOD_HANDLER)); - masm.bind(noCall); - } - } - } } private static void emitCodeBody(CompilationResultBuilder crb, LIR lir, AArch64MacroAssembler masm) { @@ -382,10 +360,8 @@ private static void emitCodeBody(CompilationResultBuilder crb, LIR lir, AArch64M * @see "http://mail.openjdk.java.net/pipermail/aarch64-port-dev/2013-September/000273.html" */ public static void emitInvalidatePlaceholder(CompilationResultBuilder crb, AArch64MacroAssembler masm) { - if (!GeneratePIC.getValue(crb.getOptions())) { - crb.blockComment("[nop for method invalidation]"); - masm.nop(); - } + crb.blockComment("[nop for method invalidation]"); + masm.nop(); } private void emitCodeSuffix(CompilationResultBuilder crb, AArch64MacroAssembler masm, FrameMap frameMap) { diff --git a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotConstantRetrievalOp.java b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotConstantRetrievalOp.java index 715df8e1ccc9..407c7a2a6698 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotConstantRetrievalOp.java +++ b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotConstantRetrievalOp.java @@ -116,7 +116,8 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { } final int before = masm.position(); - masm.bl(0); + // address is fixed up by HotSpot. + masm.bl(); final int after = masm.position(); crb.recordDirectCall(before, after, callLinkage, frameState); } diff --git a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDirectStaticCallOp.java b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDirectStaticCallOp.java index dd72b8837dbc..f0c3cdd34f78 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDirectStaticCallOp.java +++ b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDirectStaticCallOp.java @@ -62,7 +62,7 @@ final class AArch64HotSpotDirectStaticCallOp extends DirectCallOp { @Override @SuppressWarnings("try") public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { - try (CompilationResultBuilder.CallContext callContext = crb.openCallContext(invokeKind.isDirect())) { + try (CompilationResultBuilder.CallContext callContext = crb.openCallContext()) { // The mark for an invocation that uses an inline cache must be placed at the // instruction that loads the Klass from the inline cache. // For the first invocation this is set to a bitpattern that is guaranteed to never be a diff --git a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDirectVirtualCallOp.java b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDirectVirtualCallOp.java index 12a2cc9942d9..6c5ec7bfed5e 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDirectVirtualCallOp.java +++ b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDirectVirtualCallOp.java @@ -62,7 +62,7 @@ final class AArch64HotSpotDirectVirtualCallOp extends DirectCallOp { @Override @SuppressWarnings("try") public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { - try (CompilationResultBuilder.CallContext callContext = crb.openCallContext(invokeKind.isDirect())) { + try (CompilationResultBuilder.CallContext callContext = crb.openCallContext()) { // The mark for an invocation that uses an inline cache must be placed at the // instruction that loads the Klass from the inline cache. // For the first invocation this is set to a bitpattern that is guaranteed to never be a diff --git a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java index 055299c07c09..b5d3f0abd766 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java +++ b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java @@ -26,15 +26,6 @@ package org.graalvm.compiler.hotspot.aarch64; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; -import static org.graalvm.compiler.hotspot.HotSpotBackend.INITIALIZE_KLASS_BY_SYMBOL; -import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE; -import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL; -import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS; -import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL; -import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.INITIALIZE; -import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.LOAD_COUNTERS; -import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.RESOLVE; import static org.graalvm.compiler.lir.LIRValueUtil.asConstant; import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; @@ -51,10 +42,8 @@ import org.graalvm.compiler.core.aarch64.AArch64LIRGenerator; import org.graalvm.compiler.core.aarch64.AArch64LIRKindTool; import org.graalvm.compiler.core.common.CompressEncoding; -import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.calc.Condition; -import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; import org.graalvm.compiler.core.common.spi.LIRKindTool; import org.graalvm.compiler.debug.GraalError; @@ -65,9 +54,7 @@ import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult; import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; import org.graalvm.compiler.hotspot.HotSpotLockStack; -import org.graalvm.compiler.hotspot.HotSpotMarkId; import org.graalvm.compiler.hotspot.debug.BenchmarkCounters; -import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; import org.graalvm.compiler.hotspot.stubs.Stub; @@ -85,11 +72,9 @@ import org.graalvm.compiler.lir.aarch64.AArch64Move; import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreOp; import org.graalvm.compiler.lir.aarch64.AArch64PrefetchOp; -import org.graalvm.compiler.lir.aarch64.AArch64ReadTimestampCounter; import org.graalvm.compiler.lir.aarch64.AArch64RestoreRegistersOp; import org.graalvm.compiler.lir.aarch64.AArch64SaveRegistersOp; import org.graalvm.compiler.lir.gen.LIRGenerationResult; -import org.graalvm.compiler.options.OptionValues; import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.aarch64.AArch64Kind; @@ -97,7 +82,6 @@ import jdk.vm.ci.code.Register; import jdk.vm.ci.code.RegisterValue; import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant; -import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; import jdk.vm.ci.hotspot.HotSpotObjectConstant; import jdk.vm.ci.meta.AllocatableValue; import jdk.vm.ci.meta.Constant; @@ -258,7 +242,6 @@ protected boolean emitCompare(PlatformKind cmpKind, Value a, Value b, Condition @Override public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) { LIRKind inputKind = pointer.getValueKind(LIRKind.class); - LIRKindTool lirKindTool = getLIRKindTool(); assert inputKind.getPlatformKind() == AArch64Kind.QWORD; if (inputKind.isReference(0)) { // oop @@ -269,16 +252,8 @@ public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonN // metaspace pointer Variable result = newVariable(LIRKind.value(AArch64Kind.DWORD)); AllocatableValue base = Value.ILLEGAL; - OptionValues options = getResult().getLIR().getOptions(); - if (encoding.hasBase() || GeneratePIC.getValue(options)) { - if (GeneratePIC.getValue(options)) { - Variable baseAddress = newVariable(lirKindTool.getWordKind()); - AArch64HotSpotMove.BaseMove move = new AArch64HotSpotMove.BaseMove(baseAddress); - append(move); - base = baseAddress; - } else { - base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.getBase())); - } + if (encoding.hasBase()) { + base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.getBase())); } append(new AArch64HotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); return result; @@ -298,16 +273,8 @@ public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean no // metaspace pointer Variable result = newVariable(LIRKind.value(AArch64Kind.QWORD)); AllocatableValue base = Value.ILLEGAL; - OptionValues options = getResult().getLIR().getOptions(); - if (encoding.hasBase() || GeneratePIC.getValue(options)) { - if (GeneratePIC.getValue(options)) { - Variable baseAddress = newVariable(LIRKind.value(AArch64Kind.QWORD)); - AArch64HotSpotMove.BaseMove move = new AArch64HotSpotMove.BaseMove(baseAddress); - append(move); - base = baseAddress; - } else { - base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.getBase())); - } + if (encoding.hasBase()) { + base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.getBase())); } append(new AArch64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); return result; @@ -467,73 +434,6 @@ public void emitUnwind(Value exception) { append(new AArch64HotSpotUnwindOp(config, exceptionParameter)); } - @Override - public Value emitLoadObjectAddress(Constant constant) { - HotSpotObjectConstant objectConstant = (HotSpotObjectConstant) constant; - LIRKind kind = objectConstant.isCompressed() ? getLIRKindTool().getNarrowOopKind() : getLIRKindTool().getObjectKind(); - Variable result = newVariable(kind); - append(new AArch64HotSpotLoadAddressOp(result, constant, HotSpotConstantLoadAction.RESOLVE)); - return result; - } - - @Override - public Value emitLoadMetaspaceAddress(Constant constant, HotSpotConstantLoadAction action) { - HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) constant; - LIRKind kind = metaspaceConstant.isCompressed() ? getLIRKindTool().getNarrowPointerKind() : getLIRKindTool().getWordKind(); - Variable result = newVariable(kind); - append(new AArch64HotSpotLoadAddressOp(result, constant, action)); - return result; - } - - private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, Object[] notes, Constant[] constants, AllocatableValue[] constantDescriptions, LIRFrameState frameState) { - ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(foreignCall); - append(new AArch64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes)); - AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn(); - return emitMove(result); - } - - private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, AllocatableValue[] constantDescriptions, LIRFrameState frameState) { - Constant[] constants = new Constant[]{constant}; - Object[] notes = new Object[]{action}; - return emitConstantRetrieval(foreignCall, notes, constants, constantDescriptions, frameState); - } - - @Override - public Value emitResolveDynamicInvoke(Constant appendix, LIRFrameState frameState) { - AllocatableValue[] constantDescriptions = new AllocatableValue[0]; - return emitConstantRetrieval(RESOLVE_DYNAMIC_INVOKE, INITIALIZE, appendix, constantDescriptions, frameState); - } - - @Override - public Value emitLoadConfigValue(HotSpotMarkId markId, LIRKind kind) { - Variable result = newVariable(kind); - append(new AArch64HotSpotLoadConfigValueOp(markId, result)); - return result; - } - - @Override - public Value emitRandomSeed() { - Variable result = newVariable(LIRKind.value(AArch64Kind.QWORD)); - AArch64ReadTimestampCounter timestamp = new AArch64ReadTimestampCounter(result); - append(timestamp); - return result; - } - - private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, Value constantDescription, LIRFrameState frameState) { - AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)}; - return emitConstantRetrieval(foreignCall, action, constant, constantDescriptions, frameState); - } - - @Override - public Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { - return emitConstantRetrieval(RESOLVE_STRING_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState); - } - - @Override - public Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { - return emitConstantRetrieval(RESOLVE_KLASS_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState); - } - @Override public void emitReturn(JavaKind kind, Value input) { AllocatableValue operand = Value.ILLEGAL; @@ -545,17 +445,6 @@ public void emitReturn(JavaKind kind, Value input) { append(new AArch64HotSpotReturnOp(operand, getStub() != null, config, thread, getResult().requiresReservedStackAccessCheck())); } - @Override - public Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { - return emitConstantRetrieval(INITIALIZE_KLASS_BY_SYMBOL, INITIALIZE, constant, constantDescription, frameState); - } - - @Override - public Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) { - AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(klassHint), asAllocatable(methodDescription)}; - return emitConstantRetrieval(RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS, LOAD_COUNTERS, method, constantDescriptions, frameState); - } - /** * Gets the {@link Stub} this generator is generating code for or {@code null} if a stub is not * being generated. @@ -601,12 +490,6 @@ public void emitZeroMemory(Value address, Value length, boolean isAligned) { // Use DC ZVA if it's not prohibited and AArch64 HotSpot flag UseBlockZeroing is on. boolean useDcZva = !isDcZvaProhibited && flags.contains(AArch64.Flag.UseBlockZeroing); - // Set zva length negative (unknown at compile-time) for AOT compilation, since the value - // could be different on different AArch64 CPU implementations. - if (GraalOptions.ImmutableCode.getValue(getResult().getLIR().getOptions())) { - useDcZva = false; - } - emitZeroMemory(address, length, isAligned, useDcZva, zvaLength); } } diff --git a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoadAddressOp.java b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoadAddressOp.java index 3b2c7adcb164..6e88abe2ed95 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoadAddressOp.java +++ b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoadAddressOp.java @@ -27,11 +27,9 @@ import static jdk.vm.ci.code.ValueUtil.asRegister; import jdk.vm.ci.aarch64.AArch64Kind; -import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.AllocatableValue; import jdk.vm.ci.meta.Constant; -import org.graalvm.compiler.asm.aarch64.AArch64Address; import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.lir.LIRInstructionClass; @@ -68,12 +66,6 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { default: throw GraalError.shouldNotReachHere("unexpected kind: " + kind); } - if (crb.compilationResult.isImmutablePIC()) { - Register dst = asRegister(result); - masm.adrpAdd(dst); - masm.ldr(size, dst, AArch64Address.createBaseRegisterOnlyAddress(size, dst)); - } else { - masm.ldr(size, asRegister(result), masm.getPlaceholder(-1)); - } + masm.ldr(size, asRegister(result), masm.getPlaceholder(-1)); } } diff --git a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoadConfigValueOp.java b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoadConfigValueOp.java deleted file mode 100644 index 750cf8e0513b..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoadConfigValueOp.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2018, Red Hat Inc. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.aarch64; - -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; - -import org.graalvm.compiler.asm.aarch64.AArch64Address; -import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.hotspot.HotSpotMarkId; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; - -import jdk.vm.ci.aarch64.AArch64Kind; -import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.AllocatableValue; - -public final class AArch64HotSpotLoadConfigValueOp extends AArch64LIRInstruction { - - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64HotSpotLoadConfigValueOp.class); - - @Def({OperandFlag.REG}) protected AllocatableValue result; - private final HotSpotMarkId markId; - - public AArch64HotSpotLoadConfigValueOp(HotSpotMarkId markId, AllocatableValue result) { - super(TYPE); - this.result = result; - this.markId = markId; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { - if (GeneratePIC.getValue(crb.getOptions())) { - AArch64Kind kind = (AArch64Kind) result.getPlatformKind(); - Register reg = asRegister(result); - masm.adrpAdd(reg); - switch (kind) { - case BYTE: - masm.ldrs(32, 8, reg, AArch64Address.createBaseRegisterOnlyAddress(8, reg)); - break; - case WORD: - masm.ldrs(32, 16, reg, AArch64Address.createBaseRegisterOnlyAddress(16, reg)); - break; - case DWORD: - masm.ldr(32, reg, AArch64Address.createBaseRegisterOnlyAddress(32, reg)); - break; - case QWORD: - masm.ldr(64, reg, AArch64Address.createBaseRegisterOnlyAddress(64, reg)); - break; - default: - throw GraalError.unimplemented(); - } - masm.nop(); - } else { - throw GraalError.unimplemented(); - } - crb.recordMark(markId); - } - -} diff --git a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoweringProvider.java b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoweringProvider.java index b874472bdea4..a383b2e9eb02 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoweringProvider.java +++ b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoweringProvider.java @@ -67,7 +67,10 @@ public void initialize(OptionValues options, Iterable fact @Override public void lower(Node n, LoweringTool tool) { if (n instanceof IntegerDivRemNode) { - integerArithmeticSnippets.lower((IntegerDivRemNode) n, tool); + if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.LOW_TIER) { + // wait more precise stamp information + integerArithmeticSnippets.lower((IntegerDivRemNode) n, tool); + } } else if (n instanceof FloatConvertNode) { // AMD64 has custom lowerings for ConvertNodes, HotSpotLoweringProvider does not expect // to see a ConvertNode and throws an error, just do nothing here. diff --git a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java index fe39dd2c4652..0e1862fdfbac 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java +++ b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java @@ -27,7 +27,6 @@ import static jdk.vm.ci.aarch64.AArch64.zr; import static jdk.vm.ci.code.ValueUtil.asRegister; import static jdk.vm.ci.code.ValueUtil.isRegister; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; @@ -137,9 +136,8 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { Register resultRegister = asRegister(result); Register ptr = asRegister(input); Register base = (isRegister(baseRegister) ? asRegister(baseRegister) : zr); - boolean pic = GeneratePIC.getValue(crb.getOptions()); // result = (ptr - base) >> shift - if (!pic && !encoding.hasBase()) { + if (!encoding.hasBase()) { if (encoding.hasShift()) { masm.lsr(64, resultRegister, ptr, encoding.getShift()); } else { @@ -188,8 +186,7 @@ public UncompressPointer(AllocatableValue result, AllocatableValue input, Alloca public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { Register inputRegister = asRegister(input); Register resultRegister = asRegister(result); - boolean pic = GeneratePIC.getValue(crb.getOptions()); - Register base = pic || encoding.hasBase() ? asRegister(baseRegister) : null; + Register base = encoding.hasBase() ? asRegister(baseRegister) : null; emitUncompressCode(masm, inputRegister, resultRegister, base, encoding.getShift(), nonNull); } @@ -220,34 +217,12 @@ public static void emitUncompressCode(AArch64MacroAssembler masm, Register input } } - // - // private static void decompressPointer(CompilationResultBuilder crb, ARMv8MacroAssembler masm, - // Register result, - // Register ptr, long base, int shift, int alignment) { - // assert base != 0 || shift == 0 || alignment == shift; - // // result = heapBase + ptr << alignment - // Register heapBase = ARMv8.heapBaseRegister; - // // if result == 0, we make sure that it will still be 0 at the end, so that it traps when - // // loading storing a value. - // masm.cmp(32, ptr, 0); - // masm.add(64, result, heapBase, ptr, ARMv8Assembler.ExtendType.UXTX, alignment); - // masm.cmov(64, result, result, ARMv8.zr, ARMv8Assembler.ConditionFlag.NE); - // } - - public static void decodeKlassPointer(CompilationResultBuilder crb, AArch64MacroAssembler masm, Register result, Register ptr, CompressEncoding encoding) { + public static void decodeKlassPointer(AArch64MacroAssembler masm, Register result, Register ptr, CompressEncoding encoding) { try (AArch64MacroAssembler.ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); - boolean pic = GeneratePIC.getValue(crb.getOptions()); - if (pic || encoding.hasBase() || encoding.getShift() != 0) { - if (pic) { - masm.adrpAdd(scratch); - masm.ldr(64, scratch, AArch64Address.createBaseRegisterOnlyAddress(64, scratch)); - masm.add(64, result, scratch, ptr, AArch64Assembler.ExtendType.UXTX, encoding.getShift()); - crb.recordMark(HotSpotMarkId.NARROW_KLASS_BASE_ADDRESS); - } else { - masm.mov(scratch, encoding.getBase()); - masm.add(64, result, scratch, ptr, AArch64Assembler.ExtendType.UXTX, encoding.getShift()); - } + if (encoding.hasBase() || encoding.getShift() != 0) { + masm.mov(scratch, encoding.getBase()); + masm.add(64, result, scratch, ptr, AArch64Assembler.ExtendType.UXTX, encoding.getShift()); } } } diff --git a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64IndirectCallOp.java b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64IndirectCallOp.java index 0ccb9d2c8efe..bf21e69d4a7b 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64IndirectCallOp.java +++ b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64IndirectCallOp.java @@ -67,7 +67,7 @@ final class AArch64IndirectCallOp extends IndirectCallOp { @Override @SuppressWarnings("try") public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { - try (CompilationResultBuilder.CallContext callContext = crb.openCallContext(false)) { + try (CompilationResultBuilder.CallContext callContext = crb.openCallContext()) { crb.recordMark(HotSpotMarkId.INLINE_INVOKE); Register callReg = asRegister(targetAddress); assert !callReg.equals(METHOD); diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java index 7417b4ad3240..a1324d1b53dc 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java @@ -25,20 +25,14 @@ package org.graalvm.compiler.hotspot.amd64; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; - import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; import org.graalvm.compiler.core.amd64.AMD64AddressNode; import org.graalvm.compiler.core.amd64.AMD64CompressAddressLowering; import org.graalvm.compiler.core.common.CompressEncoding; import org.graalvm.compiler.core.common.type.IntegerStamp; -import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.hotspot.HotSpotMarkId; -import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode; -import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; import org.graalvm.compiler.nodes.CompressionNode; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.NodeView; @@ -57,10 +51,8 @@ import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; import org.graalvm.compiler.nodes.spi.LoopsDataProvider; -import org.graalvm.compiler.options.OptionValues; import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.JavaKind; public class AMD64HotSpotAddressLowering extends AMD64CompressAddressLowering { @@ -69,14 +61,10 @@ public class AMD64HotSpotAddressLowering extends AMD64CompressAddressLowering { private final long heapBase; private final Register heapBaseRegister; - private final GraalHotSpotVMConfig config; - private final boolean generatePIC; - public AMD64HotSpotAddressLowering(GraalHotSpotVMConfig config, Register heapBaseRegister, OptionValues options) { + public AMD64HotSpotAddressLowering(GraalHotSpotVMConfig config, Register heapBaseRegister) { this.heapBase = config.getOopEncoding().getBase(); - this.config = config; - this.generatePIC = GeneratePIC.getValue(options); - if (heapBase == 0 && !generatePIC) { + if (heapBase == 0) { this.heapBaseRegister = null; } else { this.heapBaseRegister = heapBaseRegister; @@ -91,28 +79,17 @@ protected final boolean improveUncompression(AMD64AddressNode addr, CompressionN } if (heapBaseRegister != null && encoding.getBase() == heapBase) { - if ((!generatePIC || compression.stamp(NodeView.DEFAULT) instanceof ObjectStamp) && other == null) { - // With PIC it is only legal to do for oops since the base value may be - // different at runtime. + if (other == null) { ValueNode base = compression.graph().unique(new HeapBaseNode(heapBaseRegister)); addr.setBase(base); } else { return false; } - } else if (encoding.getBase() != 0 || (generatePIC && compression.stamp(NodeView.DEFAULT) instanceof KlassPointerStamp)) { - if (generatePIC) { - if (other == null) { - ValueNode base = compression.graph().unique(new GraalHotSpotVMConfigNode(config, HotSpotMarkId.NARROW_KLASS_BASE_ADDRESS, JavaKind.Long)); - addr.setBase(base); - } else { - return false; - } + } else if (encoding.getBase() != 0) { + if (updateDisplacement(addr, encoding.getBase(), false)) { + addr.setBase(other); } else { - if (updateDisplacement(addr, encoding.getBase(), false)) { - addr.setBase(other); - } else { - return false; - } + return false; } } else { addr.setBase(other); diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java index 447ede6a1a0b..1055fde9a51d 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java @@ -30,7 +30,6 @@ import static jdk.vm.ci.amd64.AMD64.rsp; import static jdk.vm.ci.code.ValueUtil.asRegister; import static org.graalvm.compiler.core.common.GraalOptions.CanOmitFrame; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry; import org.graalvm.compiler.asm.amd64.AMD64Address; @@ -40,7 +39,6 @@ import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.amd64.AMD64NodeMatchRules; -import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; import org.graalvm.compiler.core.gen.LIRGenerationProvider; @@ -51,7 +49,6 @@ import org.graalvm.compiler.hotspot.HotSpotHostBackend; import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult; import org.graalvm.compiler.hotspot.HotSpotMarkId; -import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; import org.graalvm.compiler.hotspot.stubs.Stub; @@ -72,13 +69,11 @@ import org.graalvm.compiler.options.OptionValues; import jdk.vm.ci.amd64.AMD64; -import jdk.vm.ci.amd64.AMD64Kind; import jdk.vm.ci.code.CallingConvention; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.RegisterConfig; import jdk.vm.ci.code.StackSlot; import jdk.vm.ci.hotspot.HotSpotCallingConventionType; -import jdk.vm.ci.hotspot.HotSpotSentinelConstant; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; @@ -282,18 +277,13 @@ public void emitCodePrefix(ResolvedJavaMethod installedCodeOwner, CompilationRes if (config.useCompressedClassPointers) { Register register = r10; Register heapBase = providers.getRegisters().getHeapBaseRegister(); - AMD64HotSpotMove.decodeKlassPointer(crb, asm, register, heapBase, src, config); - if (GeneratePIC.getValue(crb.getOptions())) { - asm.movq(heapBase, asm.getPlaceholder(-1)); - crb.recordMark(HotSpotMarkId.NARROW_OOP_BASE_ADDRESS); - } else { - if (config.narrowKlassBase != 0) { - // The heap base register was destroyed above, so restore it - if (config.narrowOopBase == 0L) { - asm.xorq(heapBase, heapBase); - } else { - asm.movq(heapBase, config.narrowOopBase); - } + AMD64HotSpotMove.decodeKlassPointer(asm, register, heapBase, src, config); + if (config.narrowKlassBase != 0) { + // The heap base register was destroyed above, so restore it + if (config.narrowOopBase == 0L) { + asm.xorq(heapBase, heapBase); + } else { + asm.movq(heapBase, config.narrowOopBase); } } before = asm.cmpqAndJcc(inlineCacheKlass, register, ConditionFlag.NotEqual, null, false); @@ -305,17 +295,6 @@ public void emitCodePrefix(ResolvedJavaMethod installedCodeOwner, CompilationRes asm.align(config.codeEntryAlignment); crb.recordMark(crb.compilationResult.getEntryBCI() != -1 ? HotSpotMarkId.OSR_ENTRY : HotSpotMarkId.VERIFIED_ENTRY); - - if (GeneratePIC.getValue(crb.getOptions())) { - // Check for method state - HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; - if (!frameContext.isStub) { - crb.recordInlineDataInCodeWithNote(new HotSpotSentinelConstant(LIRKind.value(AMD64Kind.QWORD), JavaKind.Long), HotSpotConstantLoadAction.MAKE_NOT_ENTRANT); - asm.movq(AMD64.rax, asm.getPlaceholder(-1)); - int before = asm.testqAndJcc(AMD64.rax, AMD64.rax, ConditionFlag.NotZero, null, false); - AMD64Call.recordDirectCall(crb, asm, getForeignCalls().lookupForeignCall(WRONG_METHOD_HANDLER), before); - } - } } /** diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java index 4d9c705bdcb8..a38eb5084405 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java @@ -118,7 +118,7 @@ protected HotSpotHostForeignCallsProvider createForeignCalls(HotSpotJVMCIRuntime protected HotSpotSuitesProvider createSuites(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, Plugins plugins, HotSpotRegistersProvider registers, HotSpotReplacementsImpl replacements, OptionValues options) { return new AddressLoweringHotSpotSuitesProvider(new AMD64SuitesCreator(compilerConfiguration, plugins), config, runtime, - new AddressLoweringPhase(new AMD64HotSpotAddressLowering(config, registers.getHeapBaseRegister(), options))); + new AddressLoweringPhase(new AMD64HotSpotAddressLowering(config, registers.getHeapBaseRegister()))); } @Override diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDirectStaticCallOp.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDirectStaticCallOp.java index 5f81a014c748..3bbb9e0ab912 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDirectStaticCallOp.java +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotDirectStaticCallOp.java @@ -59,7 +59,7 @@ final class AMD64HotSpotDirectStaticCallOp extends DirectCallOp { @Override @SuppressWarnings("try") public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - try (CompilationResultBuilder.CallContext callContext = crb.openCallContext(invokeKind.isDirect())) { + try (CompilationResultBuilder.CallContext callContext = crb.openCallContext()) { crb.recordMark(invokeKind == InvokeKind.Static ? HotSpotMarkId.INVOKESTATIC : HotSpotMarkId.INVOKESPECIAL); if (config.supportsMethodHandleDeoptimizationEntry() && config.isMethodHandleCall((HotSpotResolvedJavaMethod) callTarget) && invokeKind != InvokeKind.Static) { crb.setNeedsMHDeoptHandler(); diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java index 3eeec699c038..f00df5dcc0ed 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java @@ -25,27 +25,16 @@ package org.graalvm.compiler.hotspot.amd64; import static jdk.vm.ci.amd64.AMD64.rbp; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; -import static org.graalvm.compiler.hotspot.HotSpotBackend.INITIALIZE_KLASS_BY_SYMBOL; -import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE; -import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL; -import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS; -import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL; -import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.INITIALIZE; -import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.LOAD_COUNTERS; -import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.RESOLVE; import java.util.ArrayList; import java.util.List; -import jdk.vm.ci.code.RegisterArray; import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; import org.graalvm.compiler.core.amd64.AMD64ArithmeticLIRGenerator; import org.graalvm.compiler.core.amd64.AMD64LIRGenerator; import org.graalvm.compiler.core.amd64.AMD64MoveFactoryBase.BackupSlotProvider; import org.graalvm.compiler.core.common.CompressEncoding; import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; import org.graalvm.compiler.core.common.spi.LIRKindTool; import org.graalvm.compiler.debug.DebugContext; @@ -57,9 +46,7 @@ import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult; import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; import org.graalvm.compiler.hotspot.HotSpotLockStack; -import org.graalvm.compiler.hotspot.HotSpotMarkId; import org.graalvm.compiler.hotspot.debug.BenchmarkCounters; -import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; import org.graalvm.compiler.hotspot.stubs.Stub; import org.graalvm.compiler.lir.LIR; @@ -78,7 +65,6 @@ import org.graalvm.compiler.lir.amd64.AMD64Move; import org.graalvm.compiler.lir.amd64.AMD64Move.MoveFromRegOp; import org.graalvm.compiler.lir.amd64.AMD64PrefetchOp; -import org.graalvm.compiler.lir.amd64.AMD64ReadTimestampCounter; import org.graalvm.compiler.lir.amd64.AMD64ReadTimestampCounterWithProcid; import org.graalvm.compiler.lir.amd64.AMD64RestoreRegistersOp; import org.graalvm.compiler.lir.amd64.AMD64SaveRegistersOp; @@ -86,19 +72,16 @@ import org.graalvm.compiler.lir.asm.CompilationResultBuilder; import org.graalvm.compiler.lir.framemap.FrameMapBuilder; import org.graalvm.compiler.lir.gen.LIRGenerationResult; -import org.graalvm.compiler.options.OptionValues; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.amd64.AMD64Kind; import jdk.vm.ci.code.CallingConvention; import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterArray; import jdk.vm.ci.code.RegisterConfig; import jdk.vm.ci.code.RegisterValue; import jdk.vm.ci.code.StackSlot; -import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; -import jdk.vm.ci.hotspot.HotSpotObjectConstant; import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.DeoptimizationAction; import jdk.vm.ci.meta.DeoptimizationReason; import jdk.vm.ci.meta.JavaConstant; @@ -425,83 +408,6 @@ public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, return result; } - @Override - public Value emitLoadObjectAddress(Constant constant) { - HotSpotObjectConstant objectConstant = (HotSpotObjectConstant) constant; - LIRKind kind = objectConstant.isCompressed() ? getLIRKindTool().getNarrowOopKind() : getLIRKindTool().getObjectKind(); - Variable result = newVariable(kind); - append(new AMD64HotSpotLoadAddressOp(result, constant, HotSpotConstantLoadAction.RESOLVE)); - return result; - } - - @Override - public Value emitLoadMetaspaceAddress(Constant constant, HotSpotConstantLoadAction action) { - HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) constant; - LIRKind kind = metaspaceConstant.isCompressed() ? getLIRKindTool().getNarrowPointerKind() : getLIRKindTool().getWordKind(); - Variable result = newVariable(kind); - append(new AMD64HotSpotLoadAddressOp(result, constant, action)); - return result; - } - - private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, Object[] notes, Constant[] constants, AllocatableValue[] constantDescriptions, LIRFrameState frameState) { - ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(foreignCall); - append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes)); - AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn(); - return emitMove(result); - } - - private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, AllocatableValue[] constantDescriptions, LIRFrameState frameState) { - Constant[] constants = new Constant[]{constant}; - Object[] notes = new Object[]{action}; - return emitConstantRetrieval(foreignCall, notes, constants, constantDescriptions, frameState); - } - - private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, Value constantDescription, LIRFrameState frameState) { - AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)}; - return emitConstantRetrieval(foreignCall, action, constant, constantDescriptions, frameState); - } - - @Override - public Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { - return emitConstantRetrieval(RESOLVE_STRING_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState); - } - - @Override - public Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { - return emitConstantRetrieval(RESOLVE_KLASS_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState); - } - - @Override - public Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) { - return emitConstantRetrieval(INITIALIZE_KLASS_BY_SYMBOL, INITIALIZE, constant, constantDescription, frameState); - } - - @Override - public Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) { - AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(klassHint), asAllocatable(methodDescription)}; - return emitConstantRetrieval(RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS, LOAD_COUNTERS, method, constantDescriptions, frameState); - } - - @Override - public Value emitResolveDynamicInvoke(Constant appendix, LIRFrameState frameState) { - AllocatableValue[] constantDescriptions = new AllocatableValue[0]; - return emitConstantRetrieval(RESOLVE_DYNAMIC_INVOKE, INITIALIZE, appendix, constantDescriptions, frameState); - } - - @Override - public Value emitLoadConfigValue(HotSpotMarkId markId, LIRKind kind) { - Variable result = newVariable(kind); - append(new AMD64HotSpotLoadConfigValueOp(markId, result)); - return result; - } - - @Override - public Value emitRandomSeed() { - AMD64ReadTimestampCounter timestamp = new AMD64ReadTimestampCounter(); - append(timestamp); - return emitMove(timestamp.getLowResult()); - } - @Override public void emitTailcall(Value[] args, Value address) { append(new AMD64TailcallOp(args, address)); @@ -611,16 +517,8 @@ public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonN // metaspace pointer Variable result = newVariable(lirKindTool.getNarrowPointerKind()); AllocatableValue base = Value.ILLEGAL; - OptionValues options = getResult().getLIR().getOptions(); - if (encoding.hasBase() || GeneratePIC.getValue(options)) { - if (GeneratePIC.getValue(options)) { - Variable baseAddress = newVariable(lirKindTool.getWordKind()); - AMD64HotSpotMove.BaseMove move = new AMD64HotSpotMove.BaseMove(baseAddress); - append(move); - base = baseAddress; - } else { - base = emitLoadConstant(lirKindTool.getWordKind(), JavaConstant.forLong(encoding.getBase())); - } + if (encoding.hasBase()) { + base = emitLoadConstant(lirKindTool.getWordKind(), JavaConstant.forLong(encoding.getBase())); } append(new AMD64Move.CompressPointerOp(result, asAllocatable(pointer), base, encoding, nonNull, getLIRKindTool())); return result; @@ -642,16 +540,8 @@ public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean no LIRKind uncompressedKind = lirKindTool.getWordKind(); Variable result = newVariable(uncompressedKind); AllocatableValue base = Value.ILLEGAL; - OptionValues options = getResult().getLIR().getOptions(); - if (encoding.hasBase() || GeneratePIC.getValue(options)) { - if (GeneratePIC.getValue(options)) { - Variable baseAddress = newVariable(uncompressedKind); - AMD64HotSpotMove.BaseMove move = new AMD64HotSpotMove.BaseMove(baseAddress); - append(move); - base = baseAddress; - } else { - base = emitLoadConstant(uncompressedKind, JavaConstant.forLong(encoding.getBase())); - } + if (encoding.hasBase()) { + base = emitLoadConstant(uncompressedKind, JavaConstant.forLong(encoding.getBase())); } append(new AMD64Move.UncompressPointerOp(result, asAllocatable(pointer), base, encoding, nonNull, lirKindTool)); return result; diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoadConfigValueOp.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoadConfigValueOp.java deleted file mode 100644 index ef03d0713ff9..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoadConfigValueOp.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.amd64; - -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; - -import org.graalvm.compiler.asm.amd64.AMD64Address; -import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.hotspot.HotSpotMarkId; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; - -import jdk.vm.ci.amd64.AMD64Kind; -import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.AllocatableValue; - -public final class AMD64HotSpotLoadConfigValueOp extends AMD64LIRInstruction { - - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotLoadConfigValueOp.class); - - @Def({OperandFlag.REG}) protected AllocatableValue result; - private final HotSpotMarkId markId; - - public AMD64HotSpotLoadConfigValueOp(HotSpotMarkId markId, AllocatableValue result) { - super(TYPE); - this.result = result; - this.markId = markId; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - if (GeneratePIC.getValue(crb.getOptions())) { - AMD64Kind kind = (AMD64Kind) result.getPlatformKind(); - Register reg = asRegister(result); - AMD64Address placeholder = masm.getPlaceholder(-1); - switch (kind) { - case BYTE: - masm.movsbl(reg, placeholder); - break; - case WORD: - masm.movswl(reg, placeholder); - break; - case DWORD: - masm.movl(reg, placeholder); - break; - case QWORD: - masm.movq(reg, placeholder); - break; - default: - throw GraalError.unimplemented(); - } - } else { - throw GraalError.unimplemented(); - } - crb.recordMark(markId); - } - -} diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java index e8357ab01efc..b7f62fe38d1e 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java @@ -24,7 +24,6 @@ */ package org.graalvm.compiler.hotspot.amd64; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.GraalArithmeticStubs; import org.graalvm.compiler.core.amd64.AMD64LoweringProviderMixin; @@ -37,9 +36,7 @@ import org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; -import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode; import org.graalvm.compiler.hotspot.replacements.HotSpotAllocationSnippets; -import org.graalvm.compiler.hotspot.replacements.profiling.ProbabilisticProfileSnippets; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.calc.FloatConvertNode; import org.graalvm.compiler.nodes.extended.ForeignCallNode; @@ -50,7 +47,6 @@ import org.graalvm.compiler.replacements.amd64.AMD64TruffleArrayUtilsWithMaskSnippets; import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode; import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation; -import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.code.TargetDescription; @@ -61,7 +57,6 @@ public class AMD64HotSpotLoweringProvider extends DefaultHotSpotLoweringProvider implements AMD64LoweringProviderMixin { private AMD64ConvertSnippets.Templates convertSnippets; - private ProbabilisticProfileSnippets.Templates profileSnippets; private AMD64X87MathSnippets.Templates mathSnippets; public AMD64HotSpotLoweringProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers, @@ -74,10 +69,6 @@ public AMD64HotSpotLoweringProvider(HotSpotGraalRuntimeProvider runtime, MetaAcc public void initialize(OptionValues options, Iterable factories, HotSpotProviders providers, GraalHotSpotVMConfig config, HotSpotAllocationSnippets.Templates allocationSnippetTemplates) { convertSnippets = new AMD64ConvertSnippets.Templates(options, factories, providers, providers.getSnippetReflection(), providers.getCodeCache().getTarget()); - if (JavaVersionUtil.JAVA_SPEC >= 11 && GeneratePIC.getValue(options)) { - // AOT only introduced in JDK 9 - profileSnippets = new ProbabilisticProfileSnippets.Templates(options, factories, providers, providers.getCodeCache().getTarget()); - } mathSnippets = new AMD64X87MathSnippets.Templates(options, factories, providers, providers.getSnippetReflection(), providers.getCodeCache().getTarget()); providers.getReplacements().registerSnippetTemplateCache( new AMD64TruffleArrayUtilsWithMaskSnippets.Templates(options, factories, providers, providers.getSnippetReflection(), providers.getCodeCache().getTarget())); @@ -91,8 +82,6 @@ public void lower(Node n, LoweringTool tool) { } if (n instanceof FloatConvertNode) { convertSnippets.lower((FloatConvertNode) n, tool); - } else if (profileSnippets != null && n instanceof ProfileNode) { - profileSnippets.lower((ProfileNode) n, tool); } else if (n instanceof UnaryMathIntrinsicNode) { lowerUnaryMath((UnaryMathIntrinsicNode) n, tool); } else { diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java index 0c4536623010..a5a251fee577 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java @@ -27,7 +27,6 @@ import static jdk.vm.ci.code.ValueUtil.asRegister; import static jdk.vm.ci.code.ValueUtil.isRegister; import static jdk.vm.ci.code.ValueUtil.isStackSlot; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; @@ -65,9 +64,6 @@ public HotSpotLoadObjectConstantOp(AllocatableValue result, HotSpotObjectConstan @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - if (GeneratePIC.getValue(crb.getOptions())) { - throw GraalError.shouldNotReachHere("Object constant load should not be happening directly"); - } boolean compressed = input.isCompressed(); if (crb.target.inlineObjects) { crb.recordInlineDataInCode(input); @@ -142,9 +138,6 @@ public HotSpotLoadMetaspaceConstantOp(AllocatableValue result, HotSpotMetaspaceC @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - if (GeneratePIC.getValue(crb.getOptions())) { - throw GraalError.shouldNotReachHere("Metaspace constant load should not be happening directly"); - } boolean compressed = input.isCompressed(); if (isRegister(result)) { if (compressed) { @@ -176,21 +169,15 @@ public AllocatableValue getResult() { } } - public static void decodeKlassPointer(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, GraalHotSpotVMConfig config) { + public static void decodeKlassPointer(AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, GraalHotSpotVMConfig config) { CompressEncoding encoding = config.getKlassEncoding(); masm.movl(register, address); if (encoding.getShift() != 0) { masm.shlq(register, encoding.getShift()); } - boolean pic = GeneratePIC.getValue(crb.getOptions()); - if (pic || encoding.hasBase()) { - if (pic) { - masm.movq(scratch, masm.getPlaceholder(-1)); - crb.recordMark(HotSpotMarkId.NARROW_KLASS_BASE_ADDRESS); - } else { - assert encoding.getBase() != 0; - masm.movq(scratch, encoding.getBase()); - } + if (encoding.hasBase()) { + assert encoding.getBase() != 0; + masm.movq(scratch, encoding.getBase()); masm.addq(register, scratch); } } diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSafepointOp.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSafepointOp.java index 9a7bb160b773..ff7ae518cfc8 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSafepointOp.java +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSafepointOp.java @@ -26,8 +26,6 @@ import static jdk.vm.ci.amd64.AMD64.rax; import static jdk.vm.ci.amd64.AMD64.rip; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; -import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; import static org.graalvm.compiler.core.common.NumUtil.isInt; import org.graalvm.compiler.asm.amd64.AMD64Address; @@ -46,8 +44,6 @@ import jdk.vm.ci.code.RegisterValue; import jdk.vm.ci.code.site.InfopointReason; import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.Value; /** @@ -68,7 +64,7 @@ public AMD64HotSpotSafepointOp(LIRFrameState state, GraalHotSpotVMConfig config, this.state = state; this.config = config; this.thread = thread; - if (config.useThreadLocalPolling || isPollingPageFar(config) || ImmutableCode.getValue(tool.getOptions())) { + if (config.useThreadLocalPolling || isPollingPageFar(config)) { temp = tool.getLIRGeneratorTool().newVariable(LIRKind.value(tool.getLIRGeneratorTool().target().arch.getWordKind())); } else { // Don't waste a register if it's unneeded @@ -100,24 +96,7 @@ private static boolean isPollingPageFar(GraalHotSpotVMConfig config) { private static void emitGlobalPoll(CompilationResultBuilder crb, AMD64MacroAssembler asm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register scratch) { assert !atReturn || state == null : "state is unneeded at return"; - if (ImmutableCode.getValue(crb.getOptions())) { - JavaKind hostWordKind = JavaKind.Long; - int alignment = hostWordKind.getBitCount() / Byte.SIZE; - JavaConstant pollingPageAddress = JavaConstant.forIntegerKind(hostWordKind, config.safepointPollingAddress); - // This move will be patched to load the safepoint page from a data segment - // co-located with the immutable code. - if (GeneratePIC.getValue(crb.getOptions())) { - asm.movq(scratch, asm.getPlaceholder(-1)); - } else { - asm.movq(scratch, (AMD64Address) crb.recordDataReferenceInCode(pollingPageAddress, alignment)); - } - final int pos = asm.position(); - crb.recordMark(atReturn ? HotSpotMarkId.POLL_RETURN_FAR : HotSpotMarkId.POLL_FAR); - if (state != null) { - crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT); - } - asm.testl(rax, new AMD64Address(scratch)); - } else if (isPollingPageFar(config)) { + if (isPollingPageFar(config)) { asm.movq(scratch, config.safepointPollingAddress); crb.recordMark(atReturn ? HotSpotMarkId.POLL_RETURN_FAR : HotSpotMarkId.POLL_FAR); final int pos = asm.position(); diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java index bc1dbe801729..f984ac60d7de 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java @@ -60,7 +60,7 @@ final class AMD64HotspotDirectVirtualCallOp extends DirectCallOp { @Override @SuppressWarnings("try") public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - try (CompilationResultBuilder.CallContext callContext = crb.openCallContext(invokeKind.isDirect())) { + try (CompilationResultBuilder.CallContext callContext = crb.openCallContext()) { // The mark for an invocation that uses an inline cache must be placed at the // instruction that loads the Klass from the inline cache. crb.recordMark(invokeKind == InvokeKind.Virtual ? HotSpotMarkId.INVOKEVIRTUAL : HotSpotMarkId.INVOKEINTERFACE); diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64IndirectCallOp.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64IndirectCallOp.java index dd6363cfd86b..68cb3917ce4d 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64IndirectCallOp.java +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64IndirectCallOp.java @@ -66,7 +66,7 @@ final class AMD64IndirectCallOp extends IndirectCallOp { @Override @SuppressWarnings("try") public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - try (CompilationResultBuilder.CallContext callContext = crb.openCallContext(false)) { + try (CompilationResultBuilder.CallContext callContext = crb.openCallContext()) { crb.recordMark(HotSpotMarkId.INLINE_INVOKE); Register callReg = asRegister(targetAddress); assert !callReg.equals(METHOD); diff --git a/compiler/src/org.graalvm.compiler.hotspot.jdk16.test/src/org/graalvm/compiler/hotspot/jdk16/test/ReferenceTest.java b/compiler/src/org.graalvm.compiler.hotspot.jdk16.test/src/org/graalvm/compiler/hotspot/jdk16/test/ReferenceTest.java index 185dfd0b8309..c3600aa4d001 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.jdk16.test/src/org/graalvm/compiler/hotspot/jdk16/test/ReferenceTest.java +++ b/compiler/src/org.graalvm.compiler.hotspot.jdk16.test/src/org/graalvm/compiler/hotspot/jdk16/test/ReferenceTest.java @@ -62,10 +62,10 @@ static boolean snippet2(PhantomReference ref, Object o) { @Test public void testPhantomReference() { Object referent = new Object(); - test("snippet2", new PhantomReference(referent, new ReferenceQueue<>()), referent); - test("snippet2", new PhantomReference(referent, new ReferenceQueue<>()), null); - test("snippet2", new PhantomReference(null, new ReferenceQueue<>()), referent); - test("snippet2", new PhantomReference(null, new ReferenceQueue<>()), null); + test("snippet2", new PhantomReference<>(referent, new ReferenceQueue<>()), referent); + test("snippet2", new PhantomReference<>(referent, new ReferenceQueue<>()), null); + test("snippet2", new PhantomReference<>(null, new ReferenceQueue<>()), referent); + test("snippet2", new PhantomReference<>(null, new ReferenceQueue<>()), null); } @Override diff --git a/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/AheadOfTimeCompilationTest.java b/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/AheadOfTimeCompilationTest.java deleted file mode 100644 index e746eae5abe9..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/AheadOfTimeCompilationTest.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.test; - -import jdk.vm.ci.aarch64.AArch64; -import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaKind; -import org.graalvm.compiler.core.common.type.Stamp; -import org.graalvm.compiler.graph.iterators.NodeIterable; -import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.NodeView; -import org.graalvm.compiler.nodes.PiNode; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; -import org.graalvm.compiler.nodes.memory.FloatingReadNode; -import org.graalvm.compiler.nodes.memory.ReadNode; -import org.graalvm.compiler.options.OptionValues; -import org.junit.Assert; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; - -import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; -import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes; - -/** - * use - * - *
- * mx unittest AheadOfTimeCompilationTest @-XX:CompileCommand='print,*AheadOfTimeCompilationTest.*'
- * 
- * - * to print disassembly. - */ -public class AheadOfTimeCompilationTest extends HotSpotGraalCompilerTest { - - public static final Object STATICFINALOBJECT = new Object(); - public static final String STATICFINALSTRING = "test string"; - - public static Object getStaticFinalObject() { - return AheadOfTimeCompilationTest.STATICFINALOBJECT; - } - - @Before - public void setUp() { - Assume.assumeFalse("skipping on AArch64", getTarget().arch instanceof AArch64); - } - - @Test - public void testStaticFinalObjectAOT() { - StructuredGraph result = compile("getStaticFinalObject", true); - assertDeepEquals(1, getConstantNodes(result).count()); - Stamp constantStamp = getConstantNodes(result).first().stamp(NodeView.DEFAULT); - Assert.assertTrue(constantStamp.toString(), constantStamp instanceof KlassPointerStamp); - int expected = runtime().getVMConfig().classMirrorIsHandle ? 3 : 2; - assertDeepEquals(expected, result.getNodes().filter(ReadNode.class).count()); - } - - @Test - public void testStaticFinalObject() { - StructuredGraph result = compile("getStaticFinalObject", false); - assertDeepEquals(1, getConstantNodes(result).count()); - assertDeepEquals(JavaKind.Object, getConstantNodes(result).first().getStackKind()); - assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count()); - } - - public static Class getClassObject() { - return AheadOfTimeCompilationTest.class; - } - - @Test - public void testClassObjectAOT() { - StructuredGraph result = compile("getClassObject", true); - - NodeIterable filter = getConstantNodes(result); - assertDeepEquals(1, filter.count()); - HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) getMetaAccess().lookupJavaType(AheadOfTimeCompilationTest.class); - assertDeepEquals(type.klass(), filter.first().asConstant()); - int expected = runtime().getVMConfig().classMirrorIsHandle ? 2 : 1; - assertDeepEquals(expected, result.getNodes().filter(ReadNode.class).count()); - } - - @Test - public void testClassObject() { - StructuredGraph result = compile("getClassObject", false); - - NodeIterable filter = getConstantNodes(result); - assertDeepEquals(1, filter.count()); - JavaConstant c = filter.first().asJavaConstant(); - Assert.assertEquals(getSnippetReflection().asObject(Class.class, c), AheadOfTimeCompilationTest.class); - - assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count()); - } - - public static Class getPrimitiveClassObject() { - return int.class; - } - - @Test - public void testPrimitiveClassObjectAOT() { - StructuredGraph result = compile("getPrimitiveClassObject", true); - NodeIterable filter = getConstantNodes(result); - assertDeepEquals(1, filter.count()); - Stamp constantStamp = filter.first().stamp(NodeView.DEFAULT); - Assert.assertTrue(constantStamp instanceof KlassPointerStamp); - int expected = runtime().getVMConfig().classMirrorIsHandle ? 3 : 2; - assertDeepEquals(expected, result.getNodes().filter(ReadNode.class).count()); - } - - @Test - public void testPrimitiveClassObject() { - StructuredGraph result = compile("getPrimitiveClassObject", false); - NodeIterable filter = getConstantNodes(result); - assertDeepEquals(1, filter.count()); - JavaConstant c = filter.first().asJavaConstant(); - Assert.assertEquals(getSnippetReflection().asObject(Class.class, c), Integer.TYPE); - - assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count()); - } - - public static String getStringObject() { - return AheadOfTimeCompilationTest.STATICFINALSTRING; - } - - @Test - public void testStringObjectAOT() { - // embedded strings are fine - testStringObjectCommon(true); - } - - @Test - public void testStringObject() { - testStringObjectCommon(false); - } - - private void testStringObjectCommon(boolean compileAOT) { - StructuredGraph result = compile("getStringObject", compileAOT); - - NodeIterable filter = getConstantNodes(result); - assertDeepEquals(1, filter.count()); - JavaConstant c = filter.first().asJavaConstant(); - Assert.assertEquals(getSnippetReflection().asObject(String.class, c), "test string"); - - assertDeepEquals(0, result.getNodes().filter(FloatingReadNode.class).count()); - assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count()); - } - - public static Boolean getBoxedBoolean() { - return Boolean.valueOf(true); - } - - @Test - public void testBoxedBooleanAOT() { - StructuredGraph result = compile("getBoxedBoolean", true); - - assertDeepEquals(0, result.getNodes().filter(FloatingReadNode.class).count()); - assertDeepEquals(0, result.getNodes().filter(PiNode.class).count()); - assertDeepEquals(1, getConstantNodes(result).count()); - ConstantNode constant = getConstantNodes(result).first(); - assertDeepEquals(JavaKind.Object, constant.getStackKind()); - - JavaConstant c = constant.asJavaConstant(); - Assert.assertEquals(getSnippetReflection().asObject(Boolean.class, c), Boolean.TRUE); - } - - @Test - public void testBoxedBoolean() { - StructuredGraph result = compile("getBoxedBoolean", false); - assertDeepEquals(0, result.getNodes().filter(FloatingReadNode.class).count()); - assertDeepEquals(0, result.getNodes().filter(PiNode.class).count()); - assertDeepEquals(1, getConstantNodes(result).count()); - ConstantNode constant = getConstantNodes(result).first(); - assertDeepEquals(JavaKind.Object, constant.getStackKind()); - - JavaConstant c = constant.asJavaConstant(); - Assert.assertEquals(getSnippetReflection().asObject(Boolean.class, c), Boolean.TRUE); - } - - @SuppressWarnings("try") - private StructuredGraph compile(String test, boolean compileAOT) { - OptionValues options = new OptionValues(getInitialOptions(), ImmutableCode, compileAOT); - StructuredGraph graph = parseEager(test, AllowAssumptions.YES, options); - compile(graph.method(), graph); - return graph; - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ArrayCopyIntrinsificationTest.java b/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ArrayCopyIntrinsificationTest.java index 117014cbff43..f13944ee997a 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ArrayCopyIntrinsificationTest.java +++ b/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ArrayCopyIntrinsificationTest.java @@ -163,7 +163,7 @@ public void testObject() { } /** - * Tests {@link ArrayCopySnippets#arraycopyGenericSnippet} with checkcast. + * Tests {@link ArrayCopySnippets#genericArraycopySnippet} with checkcast. */ @Test public void testArrayStoreException() { diff --git a/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java b/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java index bd46c26ff4a5..e0cf4eebaa95 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java +++ b/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java @@ -24,6 +24,8 @@ */ package org.graalvm.compiler.hotspot.test; +import static org.graalvm.compiler.debug.StandardPathUtilitiesProvider.DIAGNOSTIC_OUTPUT_DIRECTORY_MESSAGE_FORMAT; +import static org.graalvm.compiler.debug.StandardPathUtilitiesProvider.DIAGNOSTIC_OUTPUT_DIRECTORY_MESSAGE_REGEXP; import static org.graalvm.compiler.test.SubprocessUtil.getVMCommandLine; import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments; @@ -35,6 +37,8 @@ import java.util.Collections; import java.util.Enumeration; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -224,7 +228,10 @@ private static void testHelper(List initialProbes, List extraVmAr try { List probes = new ArrayList<>(initialProbes); - Probe diagnosticProbe = new Probe("Graal diagnostic output saved in ", 1); + String format = DIAGNOSTIC_OUTPUT_DIRECTORY_MESSAGE_FORMAT; + assert format.endsWith("'%s'") : format; + String prefix = format.substring(0, format.length() - "'%s'".length()); + Probe diagnosticProbe = new Probe(prefix, 1); probes.add(diagnosticProbe); probes.add(new Probe("Forced crash after compiling", Integer.MAX_VALUE) { @Override @@ -246,10 +253,12 @@ String test() { Assert.fail(String.format("Did not find expected occurrences of '%s' in output of command: %s%n%s", probe.substring, error, proc)); } } + + Pattern diagnosticOutputFileRE = Pattern.compile(DIAGNOSTIC_OUTPUT_DIRECTORY_MESSAGE_REGEXP); String line = diagnosticProbe.lastMatchingLine; - int substringStart = line.indexOf(diagnosticProbe.substring); - int substringLength = diagnosticProbe.substring.length(); - String diagnosticOutputZip = line.substring(substringStart + substringLength).trim(); + Matcher m = diagnosticOutputFileRE.matcher(line); + Assert.assertTrue(line, m.find()); + String diagnosticOutputZip = m.group(1); List dumpPathEntries = Arrays.asList(dumpPath.list()); diff --git a/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java b/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java index fa0691b85692..c962fdf8f8d6 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java +++ b/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java @@ -1081,7 +1081,7 @@ private void addCompilation(HotSpotResolvedJavaMethod method, Map v > 1; - return i; - } - - public static PrivilegedAction invokeDynamic2(String s) { - return s::length; - } - - static final MethodHandle objToStringMH; - - static { - MethodHandle mh = null; - try { - mh = MethodHandles.lookup().findVirtual(Object.class, "toString", MethodType.methodType(String.class)); - } catch (Exception e) { - } - objToStringMH = mh; - } - - // invokehandle - public static String invokeHandle1(Object o) throws Throwable { - return (String) objToStringMH.invokeExact(o); - } - - @Test - public void test1() { - test("invokeDynamic1", 1, 1); - } - - @Test - public void test2() { - test("invokeDynamic2", 1, 1); - } - - @Test - public void test3() { - test("invokeHandle1", 1, 1); - } - -} diff --git a/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotLazyInitializationTest.java b/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotLazyInitializationTest.java deleted file mode 100644 index b8d2db0a0a2a..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotLazyInitializationTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.test; - -import org.graalvm.compiler.core.test.GraalCompilerTest; -import org.graalvm.compiler.hotspot.meta.HotSpotAOTClassInitializationPlugin; -import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; -import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; -import org.junit.Assert; -import org.junit.Assume; -import org.junit.Test; - -import jdk.vm.ci.meta.ResolvedJavaMethod; - -public class HotSpotLazyInitializationTest extends GraalCompilerTest { - - HotSpotAOTClassInitializationPlugin classInitPlugin = new HotSpotAOTClassInitializationPlugin(); - - @Override - protected Plugins getDefaultGraphBuilderPlugins() { - Plugins plugins = super.getDefaultGraphBuilderPlugins(); - plugins.setClassInitializationPlugin(classInitPlugin); - return plugins; - } - - static boolean initializerRun = false; - - static class X { - static { - initializerRun = true; - } - - static void foo() { - } - } - - public static void invokeStatic() { - X.foo(); - } - - // If constant pool can do eager resolve without eager initialization, then fail if the compiler - // causes the static initializer to run. - private void test(String name) { - ResolvedJavaMethod method = getResolvedJavaMethod(name); - Assume.assumeTrue("skipping for old JVMCI", classInitPlugin.supportsLazyInitialization(method.getConstantPool())); - parseEager(method, AllowAssumptions.NO); - Assert.assertFalse(initializerRun); - } - - @Test - public void test1() { - test("invokeStatic"); - } - -} diff --git a/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/LoadJavaMirrorWithKlassTest.java b/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/LoadJavaMirrorWithKlassTest.java deleted file mode 100644 index 44508199cc70..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/LoadJavaMirrorWithKlassTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.test; - -import java.util.Objects; - -import org.junit.Test; - -import org.graalvm.compiler.core.common.GraalOptions; -import org.graalvm.compiler.core.test.GraalCompilerTest; -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.phases.tiers.Suites; - -import jdk.vm.ci.meta.JavaKind; - -public class LoadJavaMirrorWithKlassTest extends GraalCompilerTest { - - private static class Wrapper { - private Class clazz; - - @Override - public boolean equals(Object obj) { - if (obj instanceof Wrapper) { - return Objects.equals(this.clazz, ((Wrapper) obj).clazz); - } else { - return false; - } - } - - @Override - public int hashCode() { - return clazz.hashCode(); - } - - @Override - public String toString() { - return "Wrapper-" + clazz; - } - } - - @Override - @SuppressWarnings("try") - protected Suites createSuites(OptionValues options) { - return super.createSuites(getOptions()); - } - - private static OptionValues getOptions() { - return new OptionValues(getInitialOptions(), GraalOptions.ImmutableCode, true); - } - - @Override - protected void checkLowTierGraph(StructuredGraph graph) { - for (ConstantNode constantNode : graph.getNodes().filter(ConstantNode.class)) { - assert constantNode.asJavaConstant() == null || constantNode.asJavaConstant().getJavaKind() != JavaKind.Object || - constantNode.asJavaConstant().isDefaultForKind() : "Found unexpected object constant " + - constantNode + ", this should have been removed by the LoadJavaMirrorWithKlassPhase."; - } - } - - public static Class classConstant() { - return Wrapper.class; - } - - @Test - public void testClassConstant() { - test(getOptions(), "classConstant"); - } - - public static Class primitiveClassConstant() { - return int.class; - } - - @Test - public void testPrimitiveClassConstant() { - test(getOptions(), "primitiveClassConstant"); - } - - public static Wrapper compressedClassConstant(Wrapper w) { - w.clazz = Wrapper.class; - return w; - } - - @Test - public void testCompressedClassConstant() { - ArgSupplier arg = () -> new Wrapper(); - test(getOptions(), "compressedClassConstant", arg); - } - - public static Wrapper compressedPrimitiveClassConstant(Wrapper w) { - w.clazz = int.class; - return w; - } - - @Test - public void testCompressedPrimitiveClassConstant() { - ArgSupplier arg = () -> new Wrapper(); - test(getOptions(), "compressedPrimitiveClassConstant", arg); - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ReplaceConstantNodesPhaseTest.java b/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ReplaceConstantNodesPhaseTest.java deleted file mode 100644 index 796abfceeda3..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ReplaceConstantNodesPhaseTest.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.test; - -import org.graalvm.compiler.core.common.GraalOptions; -import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.hotspot.meta.HotSpotAOTClassInitializationPlugin; -import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; -import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; -import org.graalvm.compiler.hotspot.phases.LoadJavaMirrorWithKlassPhase; -import org.graalvm.compiler.hotspot.phases.aot.EliminateRedundantInitializationPhase; -import org.graalvm.compiler.hotspot.phases.aot.ReplaceConstantNodesPhase; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; -import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; -import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.phases.common.CanonicalizerPhase; -import org.graalvm.compiler.phases.common.LoweringPhase; -import org.graalvm.compiler.phases.tiers.HighTierContext; -import org.junit.Assert; -import org.junit.Test; - -public class ReplaceConstantNodesPhaseTest extends HotSpotGraalCompilerTest { - private final GraalHotSpotVMConfig config = runtime().getVMConfig(); - - @Override - protected Plugins getDefaultGraphBuilderPlugins() { - Plugins plugins = super.getDefaultGraphBuilderPlugins(); - plugins.setClassInitializationPlugin(new HotSpotAOTClassInitializationPlugin()); - return plugins; - } - - public static class X { - public static int x; - public static int y; - public static int z; - public static Object o; - } - - public static class Y extends X { - public static int a; - public static int b; - } - - public static int a; - - public static void assignFields() { - X.x = 1; - X.y = 2; - X.z = 3; - } - - public static void assignFieldsInBranches(boolean x) { - if (x) { - X.y = 1; - } else { - X.z = 2; - } - } - - public static void assignFieldsWithDominatingInit(boolean x) { - X.x = 1; - if (x) { - X.y = 2; - } else { - X.z = 3; - } - } - - public static void assignString() { - X.o = "foo"; - } - - public static void assignToParentAndChild() { - Y.a = 1; - X.x = 2; - } - - public static void assignToThis() { - a = 1; - } - - public static void assignFieldsWithDominatingInitOfParent(boolean x) { - Y.a = 1; - if (x) { - X.y = 2; - } else { - X.z = 3; - } - Y.b = 4; - } - - private void test(String name, int expectedInits, int expectedResolves, int expectedLoads) { - StructuredGraph graph = parseEager(name, AllowAssumptions.NO, new OptionValues(getInitialOptions(), GraalOptions.GeneratePIC, true)); - HighTierContext highTierContext = getDefaultHighTierContext(); - CanonicalizerPhase canonicalizer = createCanonicalizerPhase(); - new EliminateRedundantInitializationPhase().apply(graph, highTierContext); - new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highTierContext); - new LoadJavaMirrorWithKlassPhase(config).apply(graph, highTierContext); - new ReplaceConstantNodesPhase(true, false).apply(graph, highTierContext); - Assert.assertEquals(expectedInits, graph.getNodes().filter(InitializeKlassNode.class).count()); - Assert.assertEquals(expectedResolves, graph.getNodes().filter(ResolveConstantNode.class).count()); - Assert.assertEquals(expectedLoads, graph.getNodes().filter(LoadConstantIndirectlyNode.class).count()); - } - - @Test - public void test1() { - test("assignFields", 1, 0, 0); - } - - @Test - public void test2() { - test("assignFieldsWithDominatingInit", 1, 0, 0); - } - - @Test - public void test3() { - test("assignString", 1, 1, 0); - } - - @Test - public void test4() { - test("assignToParentAndChild", 1, 1, 0); - } - - @Test - public void test5() { - test("assignToThis", 0, 0, 1); - } - - @Test - public void test6() { - test("assignFieldsWithDominatingInitOfParent", 1, 1, 0); - } - - @Test - public void test7() { - test("assignFieldsInBranches", 2, 1, 0); - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/AOTGraalHotSpotVMConfig.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/AOTGraalHotSpotVMConfig.java deleted file mode 100644 index 4e28d14939d5..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/AOTGraalHotSpotVMConfig.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot; - -import org.graalvm.compiler.core.common.CompressEncoding; - -import jdk.vm.ci.hotspot.HotSpotVMConfigStore; - -public class AOTGraalHotSpotVMConfig extends GraalHotSpotVMConfig { - private final CompressEncoding aotOopEncoding; - private final CompressEncoding aotKlassEncoding; - - public AOTGraalHotSpotVMConfig(HotSpotVMConfigStore store) { - super(store); - // AOT captures VM settings during compilation. For compressed oops this - // presents a problem for the case when the VM selects a zero-shift mode - // (i.e., when the heap is less than 4G). Compiling an AOT binary with - // zero-shift limits its usability. As such we force the shift to be - // always equal to alignment to avoid emitting zero-shift AOT code. - CompressEncoding vmOopEncoding = super.getOopEncoding(); - aotOopEncoding = new CompressEncoding(vmOopEncoding.getBase(), logMinObjAlignment()); - CompressEncoding vmKlassEncoding = super.getKlassEncoding(); - aotKlassEncoding = new CompressEncoding(vmKlassEncoding.getBase(), logKlassAlignment); - assert check(); - reportErrors(); - } - - @Override - public CompressEncoding getOopEncoding() { - return aotOopEncoding; - } - - @Override - public CompressEncoding getKlassEncoding() { - return aotKlassEncoding; - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerRuntimeHotSpotVMConfig.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerRuntimeHotSpotVMConfig.java deleted file mode 100644 index ba41bf7cd9e9..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerRuntimeHotSpotVMConfig.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot; - -import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; -import jdk.vm.ci.hotspot.HotSpotVMConfigStore; - -/** - * Used to access native configuration details for static compilation support. - */ -public class CompilerRuntimeHotSpotVMConfig extends HotSpotVMConfigAccess { - - public CompilerRuntimeHotSpotVMConfig(HotSpotVMConfigStore store) { - super(store); - } - - public final long resolveStringBySymbol = getAddress("CompilerRuntime::resolve_string_by_symbol"); - public final long resolveDynamicInvoke = getAddress("CompilerRuntime::resolve_dynamic_invoke"); - public final long resolveKlassBySymbol = getAddress("CompilerRuntime::resolve_klass_by_symbol"); - public final long resolveMethodBySymbolAndLoadCounters = getAddress("CompilerRuntime::resolve_method_by_symbol_and_load_counters"); - public final long initializeKlassBySymbol = getAddress("CompilerRuntime::initialize_klass_by_symbol"); - public final long invocationEvent = getAddress("CompilerRuntime::invocation_event"); - public final long backedgeEvent = getAddress("CompilerRuntime::backedge_event"); -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/EncodedSnippets.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/EncodedSnippets.java index b7da7658fcfc..6cfa8986e687 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/EncodedSnippets.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/EncodedSnippets.java @@ -410,7 +410,7 @@ static class SymbolicEncodedGraph extends EncodedGraph { private final String originalMethod; SymbolicEncodedGraph(byte[] encoding, int startOffset, Object[] objects, NodeClass[] types, String originalMethod, ResolvedJavaType... accessingClasses) { - super(encoding, startOffset, objects, types, null, null, null, false, false); + super(encoding, startOffset, objects, types, null, null, false, false); this.accessingClasses = accessingClasses; this.originalMethod = originalMethod; } diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java index 9cb08c907359..8f2114639e5b 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java @@ -93,24 +93,8 @@ public CompressEncoding getKlassEncoding() { public final boolean cAssertions = getConstant("ASSERT", Boolean.class); public final int codeEntryAlignment = getFlag("CodeEntryAlignment", Integer.class); - public final boolean enableContended = getFlag("EnableContended", Boolean.class); - public final boolean restrictContended = getFlag("RestrictContended", Boolean.class); - public final int contendedPaddingWidth = getFlag("ContendedPaddingWidth", Integer.class); - public final int fieldsAllocationStyle; - public final boolean compactFields; - { - // JDK-8236224 - if (JDK >= 15) { - fieldsAllocationStyle = 1; - compactFields = true; - } else { - fieldsAllocationStyle = getFlag("FieldsAllocationStyle", Integer.class); - compactFields = getFlag("CompactFields", Boolean.class); - } - } + public final boolean verifyOops = getFlag("VerifyOops", Boolean.class); - public final boolean ciTime = getFlag("CITime", Boolean.class); - public final boolean ciTimeEach = getFlag("CITimeEach", Boolean.class); public final boolean dontCompileHugeMethods = getFlag("DontCompileHugeMethods", Boolean.class); public final int hugeMethodLimit = getFlag("HugeMethodLimit", Integer.class); public final boolean printInlining = getFlag("PrintInlining", Boolean.class); @@ -118,7 +102,6 @@ public CompressEncoding getKlassEncoding() { public final boolean inlineNotify = JDK > 8; public final boolean useFastLocking = getFlag("JVMCIUseFastLocking", Boolean.class); public final boolean forceUnreachable = getFlag("ForceUnreachable", Boolean.class); - public final int codeSegmentSize = getFlag("CodeCacheSegmentSize", Integer.class); public final boolean foldStableValues = getFlag("FoldStableValues", Boolean.class); public final int maxVectorSize = getFlag("MaxVectorSize", Integer.class); @@ -128,6 +111,7 @@ public CompressEncoding getKlassEncoding() { public final boolean useTLAB = getFlag("UseTLAB", Boolean.class); public final boolean useBiasedLocking = getFlag("UseBiasedLocking", Boolean.class); public final boolean usePopCountInstruction = getFlag("UsePopCountInstruction", Boolean.class); + public final boolean useUnalignedAccesses = getFlag("UseUnalignedAccesses", Boolean.class, false, JDK >= 9); public final boolean useAESIntrinsics = getFlag("UseAESIntrinsics", Boolean.class); public final boolean useAESCTRIntrinsics = getFlag("UseAESCTRIntrinsics", Boolean.class, false, (JDK == 8 && !IS_OPENJDK) || JDK >= 9); public final boolean useCRC32Intrinsics = getFlag("UseCRC32Intrinsics", Boolean.class); @@ -238,10 +222,6 @@ public long gcTotalCollectionsAddress() { public final int narrowOopShift = getFieldValue("CompilerToVM::Data::Universe_narrow_oop_shift", Integer.class, "int"); public final int objectAlignment = getFlag("ObjectAlignmentInBytes", Integer.class); - public final int minObjAlignment() { - return objectAlignment / heapWordSize; - } - public final int logMinObjAlignment() { return (int) (Math.log(objectAlignment) / Math.log(2)); } @@ -252,7 +232,6 @@ public final int logMinObjAlignment() { public final int logKlassAlignment = getConstant("LogKlassAlignmentInBytes", Integer.class); public final int stackShadowPages = getFlag("StackShadowPages", Integer.class); - public final int stackReservedPages = getFlag("StackReservedPages", Integer.class, 0, JDK >= 9); public final boolean useStackBanging = getFlag("UseStackBanging", Boolean.class, true, JDK < 17); public final int stackBias = getConstant("STACK_BIAS", Integer.class, 0, JDK < 15); public final int vmPageSize = getFieldValue("CompilerToVM::Data::vm_page_size", Integer.class, "int"); @@ -261,8 +240,6 @@ public final int logMinObjAlignment() { public final int hubOffset = getFieldOffset("oopDesc::_metadata._klass", Integer.class, "Klass*"); public final int prototypeMarkWordOffset = getFieldOffset("Klass::_prototype_header", Integer.class, markWord); - public final int subklassOffset = getFieldOffset("Klass::_subklass", Integer.class, "Klass*"); - public final int nextSiblingOffset = getFieldOffset("Klass::_next_sibling", Integer.class, "Klass*"); public final int superCheckOffsetOffset = getFieldOffset("Klass::_super_check_offset", Integer.class, "juint"); public final int secondarySuperCacheOffset = getFieldOffset("Klass::_secondary_super_cache", Integer.class, "Klass*"); public final int secondarySupersOffset = getFieldOffset("Klass::_secondary_supers", Integer.class, "Array*"); @@ -288,32 +265,12 @@ public final int logMinObjAlignment() { public final int klassLayoutHelperNeutralValue = getConstant("Klass::_lh_neutral_value", Integer.class); public final int layoutHelperLog2ElementSizeShift = getConstant("Klass::_lh_log2_element_size_shift", Integer.class); public final int layoutHelperLog2ElementSizeMask = getConstant("Klass::_lh_log2_element_size_mask", Integer.class); - public final int layoutHelperElementTypeShift = getConstant("Klass::_lh_element_type_shift", Integer.class); - public final int layoutHelperElementTypeMask = getConstant("Klass::_lh_element_type_mask", Integer.class); public final int layoutHelperHeaderSizeShift = getConstant("Klass::_lh_header_size_shift", Integer.class); public final int layoutHelperHeaderSizeMask = getConstant("Klass::_lh_header_size_mask", Integer.class); - public final int layoutHelperArrayTagShift = getConstant("Klass::_lh_array_tag_shift", Integer.class); - public final int layoutHelperArrayTagTypeValue = getConstant("Klass::_lh_array_tag_type_value", Integer.class); - public final int layoutHelperArrayTagObjectValue = getConstant("Klass::_lh_array_tag_obj_value", Integer.class); - - /** - * This filters out the bit that differentiates a type array from an object array. - */ - public int layoutHelperElementTypePrimitiveInPlace() { - return (layoutHelperArrayTagTypeValue & ~layoutHelperArrayTagObjectValue) << layoutHelperArrayTagShift; - } - - public final int vtableEntrySize = getFieldValue("CompilerToVM::Data::sizeof_vtableEntry", Integer.class, "int"); - public final int vtableEntryMethodOffset = getFieldOffset("vtableEntry::_method", Integer.class, "Method*"); public final int instanceKlassInitStateOffset = getFieldOffset("InstanceKlass::_init_state", Integer.class, "u1"); public final int instanceKlassInitThreadOffset = getFieldOffset("InstanceKlass::_init_thread", Integer.class, "Thread*", -1, JDK == 8 || JDK >= 15 || (JVMCI && jvmciGE(JVMCI_20_0_b03))); - public final int instanceKlassConstantsOffset = getFieldOffset("InstanceKlass::_constants", Integer.class, "ConstantPool*"); - public final int instanceKlassFieldsOffset = getFieldOffset("InstanceKlass::_fields", Integer.class, "Array*"); - public final int klassVtableStartOffset = getFieldValue("CompilerToVM::Data::Klass_vtable_start_offset", Integer.class, "int"); - public final int klassVtableLengthOffset = getFieldValue("CompilerToVM::Data::Klass_vtable_length_offset", Integer.class, "int"); - public final int instanceKlassStateLinked = getConstant("InstanceKlass::linked", Integer.class); public final int instanceKlassStateBeingInitialized = getConstant("InstanceKlass::being_initialized", Integer.class, -1, JDK == 8 || (JVMCI ? jvmciGE(JVMCI_20_0_b03) : JDK >= 14)); public final int instanceKlassStateFullyInitialized = getConstant("InstanceKlass::fully_initialized", Integer.class); @@ -328,32 +285,13 @@ public final int arrayOopDescLengthOffset() { return useCompressedClassPointers ? hubOffset + narrowKlassSize : arrayOopDescSize; } - public final int arrayU1LengthOffset = getFieldOffset("Array::_length", Integer.class, "int"); - public final int arrayU1DataOffset = getFieldOffset("Array::_data", Integer.class); - public final int arrayU2DataOffset = getFieldOffset("Array::_data", Integer.class); public final int metaspaceArrayLengthOffset = getFieldOffset("Array::_length", Integer.class, "int"); public final int metaspaceArrayBaseOffset = getFieldOffset("Array::_data[0]", Integer.class, "Klass*"); public final int arrayClassElementOffset = getFieldOffset("ObjArrayKlass::_element_klass", Integer.class, "Klass*"); - public final int fieldInfoAccessFlagsOffset = getConstant("FieldInfo::access_flags_offset", Integer.class); - public final int fieldInfoNameIndexOffset = getConstant("FieldInfo::name_index_offset", Integer.class); - public final int fieldInfoSignatureIndexOffset = getConstant("FieldInfo::signature_index_offset", Integer.class); - public final int fieldInfoInitvalIndexOffset = getConstant("FieldInfo::initval_index_offset", Integer.class); - public final int fieldInfoLowPackedOffset = getConstant("FieldInfo::low_packed_offset", Integer.class); - public final int fieldInfoHighPackedOffset = getConstant("FieldInfo::high_packed_offset", Integer.class); - public final int fieldInfoFieldSlots = getConstant("FieldInfo::field_slots", Integer.class); - - public final int fieldInfoTagSize = getConstant("FIELDINFO_TAG_SIZE", Integer.class); - - public final int jvmAccMonitorMatch = getConstant("JVM_ACC_MONITOR_MATCH", Integer.class); - public final int jvmAccHasMonitorBytecodes = getConstant("JVM_ACC_HAS_MONITOR_BYTECODES", Integer.class); public final int jvmAccHasFinalizer = getConstant("JVM_ACC_HAS_FINALIZER", Integer.class); - public final int jvmAccFieldInternal = getConstant("JVM_ACC_FIELD_INTERNAL", Integer.class); - public final int jvmAccFieldStable = getConstant("JVM_ACC_FIELD_STABLE", Integer.class); - public final int jvmAccFieldHasGenericSignature = getConstant("JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE", Integer.class); public final int jvmAccWrittenFlags = getConstant("JVM_ACC_WRITTEN_FLAGS", Integer.class); - public final int jvmAccSynthetic = getConstant("JVM_ACC_SYNTHETIC", Integer.class); public final int jvmAccIsHiddenClass = getConstant("JVM_ACC_IS_HIDDEN_CLASS", Integer.class, 0, JDK >= 15); // JDK-8219607 public final int jvmciCompileStateCanPostOnExceptionsOffset = getJvmciJvmtiCapabilityOffset("_jvmti_can_post_on_exceptions"); @@ -431,37 +369,6 @@ public boolean requiresReservedStackCheck(List methods) { return false; } - /** - * An invalid value for {@link #rtldDefault}. - */ - public static final long INVALID_RTLD_DEFAULT_HANDLE = 0xDEADFACE; - - /** - * Address of the library lookup routine. The C signature of this routine is: - * - *
-     *     void* (const char *filename, char *ebuf, int ebuflen)
-     * 
- */ - public final long dllLoad = getAddress("os::dll_load"); - - /** - * Address of the library lookup routine. The C signature of this routine is: - * - *
-     *     void* (void* handle, const char* name)
-     * 
- */ - public final long dllLookup = getAddress("os::dll_lookup"); - - /** - * A pseudo-handle which when used as the first argument to {@link #dllLookup} means lookup will - * return the first occurrence of the desired symbol using the default library search order. If - * this field is {@value #INVALID_RTLD_DEFAULT_HANDLE}, then this capability is not supported on - * the current platform. - */ - public final long rtldDefault = getAddress("RTLD_DEFAULT", INVALID_RTLD_DEFAULT_HANDLE, osName.equals("darwin") || osName.equals("linux")); - /** * This field is used to pass exception objects into and out of the runtime system during * exception handling for compiled code. @@ -507,19 +414,14 @@ public int threadLastJavaFpOffset() { return javaThreadAnchorOffset + getFieldOffset("JavaFrameAnchor::_last_Java_fp", Integer.class, "intptr_t*"); } - public final int runtimeCallStackSize = getConstant("frame::arg_reg_save_area_bytes", Integer.class, 0, osArch.equals("amd64")); public final int frameInterpreterFrameSenderSpOffset = getConstant("frame::interpreter_frame_sender_sp_offset", Integer.class, 0, osArch.equals("amd64")); public final int frameInterpreterFrameLastSpOffset = getConstant("frame::interpreter_frame_last_sp_offset", Integer.class, 0, osArch.equals("amd64")); public final int osThreadInterruptedOffset = getFieldOffset("OSThread::_interrupted", Integer.class, "jint", Integer.MAX_VALUE, JDK < 14); - public final long markWordHashShift = getConstant(markWordField("hash_shift"), Long.class); - public final int biasedLockMaskInPlace = getConstant(markWordField("biased_lock_mask_in_place"), Integer.class); public final int ageMaskInPlace = getConstant(markWordField("age_mask_in_place"), Integer.class); public final int epochMaskInPlace = getConstant(markWordField("epoch_mask_in_place"), Integer.class); - public final long markWordHashMask = getConstant(markWordField("hash_mask"), Long.class); - public final long markWordHashMaskInPlace = getConstant(markWordField("hash_mask_in_place"), Long.class); public final int unlockedMask = getConstant(markWordField("unlocked_value"), Integer.class); public final int monitorMask = getConstant(markWordField("monitor_value"), Integer.class, -1, gr21761); @@ -535,22 +437,6 @@ public int threadLastJavaFpOffset() { public final int markWordNoHashInPlace = getConstant(markWordField("no_hash_in_place"), Integer.class); public final int markWordNoLockInPlace = getConstant(markWordField("no_lock_in_place"), Integer.class); - /** - * See {@code markOopDesc::prototype()}/{@code markWord::prototype()}. - */ - public long arrayPrototypeMarkWord() { - return markWordNoHashInPlace | markWordNoLockInPlace; - } - - /** - * See {@code markOopDesc::copy_set_hash()}/{@code markWord::copy_set_hash()}. - */ - public long tlabIntArrayMarkWord() { - long tmp = arrayPrototypeMarkWord() & (~markWordHashMaskInPlace); - tmp |= ((0x2 & markWordHashMask) << markWordHashShift); - return tmp; - } - private static String markWordField(String simpleName) { return (JDK < 14 ? "markOopDesc::" : "markWord::") + simpleName; } @@ -565,35 +451,15 @@ private static String markWordField(String simpleName) { */ public final int uninitializedIdentityHashCodeValue = getConstant(markWordField("no_hash"), Integer.class); - public final int methodAccessFlagsOffset = getFieldOffset("Method::_access_flags", Integer.class, "AccessFlags"); - public final int methodConstMethodOffset = getFieldOffset("Method::_constMethod", Integer.class, "ConstMethod*"); - public final int methodIntrinsicIdOffset = getFieldOffset("Method::_intrinsic_id", Integer.class, JDK <= 8 ? "u1" : "u2"); - public final int methodFlagsOffset = getFieldOffset("Method::_flags", Integer.class, JDK <= 8 ? "u1" : "u2"); - public final int methodVtableIndexOffset = getFieldOffset("Method::_vtable_index", Integer.class, "int"); - - public final int methodCountersOffset = getFieldOffset("Method::_method_counters", Integer.class, "MethodCounters*"); - public final int methodDataOffset = getFieldOffset("Method::_method_data", Integer.class, "MethodData*"); public final int methodCompiledEntryOffset = getFieldOffset("Method::_from_compiled_entry", Integer.class, "address"); - public final int methodCodeOffset = getFieldOffset("Method::_code", Integer.class, JDK <= 8 ? "nmethod*" : "CompiledMethod*"); - - public final int methodFlagsCallerSensitive = getConstant("Method::_caller_sensitive", Integer.class); - public final int methodFlagsForceInline = getConstant("Method::_force_inline", Integer.class); - public final int methodFlagsDontInline = getConstant("Method::_dont_inline", Integer.class); - public final int methodFlagsHidden = getConstant("Method::_hidden", Integer.class); - public final int nonvirtualVtableIndex = getConstant("Method::nonvirtual_vtable_index", Integer.class); - public final int invalidVtableIndex = getConstant("Method::invalid_vtable_index", Integer.class); public final int invocationCounterOffset = getFieldOffset("MethodCounters::_invocation_counter", Integer.class, "InvocationCounter"); public final int backedgeCounterOffset = getFieldOffset("MethodCounters::_backedge_counter", Integer.class, "InvocationCounter"); public final int invocationCounterIncrement = JDK <= 8 ? 0 : getConstant("InvocationCounter::count_increment", Integer.class); public final int invocationCounterShift = JDK <= 8 ? 0 : getConstant("InvocationCounter::count_shift", Integer.class); - public final int nmethodEntryOffset = getFieldOffset("nmethod::_verified_entry_point", Integer.class, "address"); public final int compilationLevelFullOptimization = getConstant("CompLevel_full_optimization", Integer.class); - public final int constantPoolSize = getFieldValue("CompilerToVM::Data::sizeof_ConstantPool", Integer.class, "int"); - public final int constantPoolLengthOffset = getFieldOffset("ConstantPool::_length", Integer.class, "int"); - public final int heapWordSize = getConstant("HeapWordSize", Integer.class); /** @@ -630,7 +496,7 @@ private static String markWordField(String simpleName) { // G1 Collector Related Values. public final byte dirtyCardValue; public final byte g1YoungCardValue; - public final int g1SATBQueueMarkingOffset; + public final int g1SATBQueueMarkingActiveOffset; public final int g1SATBQueueIndexOffset; public final int g1SATBQueueBufferOffset; public final int g1CardQueueIndexOffset; @@ -649,13 +515,13 @@ private static String markWordField(String simpleName) { g1YoungCardValue = getFieldValue("CompilerToVM::Data::g1_young_card", Byte.class, "int"); g1CardQueueIndexOffset = javaThreadDirtyCardQueueOffset + dirtyCardQueueIndexOffset; g1CardQueueBufferOffset = javaThreadDirtyCardQueueOffset + dirtyCardQueueBufferOffset; - g1SATBQueueMarkingOffset = javaThreadSatbMarkQueueOffset + satbMarkQueueActiveOffset; + g1SATBQueueMarkingActiveOffset = javaThreadSatbMarkQueueOffset + satbMarkQueueActiveOffset; g1SATBQueueIndexOffset = javaThreadSatbMarkQueueOffset + satbMarkQueueIndexOffset; g1SATBQueueBufferOffset = javaThreadSatbMarkQueueOffset + satbMarkQueueBufferOffset; } else { dirtyCardValue = getConstant("CardTable::dirty_card", Byte.class); g1YoungCardValue = getConstant("G1CardTable::g1_young_gen", Byte.class); - g1SATBQueueMarkingOffset = getConstant("G1ThreadLocalData::satb_mark_queue_active_offset", Integer.class); + g1SATBQueueMarkingActiveOffset = getConstant("G1ThreadLocalData::satb_mark_queue_active_offset", Integer.class); g1SATBQueueIndexOffset = getConstant("G1ThreadLocalData::satb_mark_queue_index_offset", Integer.class); g1SATBQueueBufferOffset = getConstant("G1ThreadLocalData::satb_mark_queue_buffer_offset", Integer.class); g1CardQueueIndexOffset = getConstant("G1ThreadLocalData::dirty_card_queue_index_offset", Integer.class); @@ -669,7 +535,6 @@ private static String markWordField(String simpleName) { public final int basicLockSize = getFieldValue("CompilerToVM::Data::sizeof_BasicLock", Integer.class, "int"); public final int basicLockDisplacedHeaderOffset = getFieldOffset("BasicLock::_displaced_header", Integer.class, markWord); - public final int threadAllocatedBytesOffset = getFieldOffset("Thread::_allocated_bytes", Integer.class, "jlong"); public final int threadPollingPageOffset; { // JDK-8237497 @@ -685,16 +550,9 @@ private static String markWordField(String simpleName) { } } - public final int tlabRefillWasteIncrement = getFlag("TLABWasteIncrement", Integer.class); - - private final int threadLocalAllocBufferStartOffset = getFieldOffset("ThreadLocalAllocBuffer::_start", Integer.class, "HeapWord*"); private final int threadLocalAllocBufferEndOffset = getFieldOffset("ThreadLocalAllocBuffer::_end", Integer.class, "HeapWord*"); private final int threadLocalAllocBufferTopOffset = getFieldOffset("ThreadLocalAllocBuffer::_top", Integer.class, "HeapWord*"); - public int threadTlabStartOffset() { - return threadTlabOffset + threadLocalAllocBufferStartOffset; - } - public int threadTlabEndOffset() { return threadTlabOffset + threadLocalAllocBufferEndOffset; } @@ -703,10 +561,6 @@ public int threadTlabTopOffset() { return threadTlabOffset + threadLocalAllocBufferTopOffset; } - public final int tlabAlignmentReserve = getFieldValue("CompilerToVM::Data::ThreadLocalAllocBuffer_alignment_reserve", Integer.class, "size_t"); - - public final boolean tlabStats = getFlag("TLABStats", Boolean.class); - // We set 0x10 as default value to disable DC ZVA if this field is not present in HotSpot. // ARMv8-A architecture reference manual D12.2.35 Data Cache Zero ID register says: // * BS, bits [3:0] indicate log2 of the DC ZVA block size in (4-byte) words. @@ -716,13 +570,6 @@ public int threadTlabTopOffset() { public final int zvaLength = getFieldValue("VM_Version::_zva_length", Integer.class, "int", 0, JDK >= 16 && osArch.equals("aarch64")); - // FIXME This is only temporary until the GC code is changed. - public final boolean inlineContiguousAllocationSupported = getFieldValue("CompilerToVM::Data::_supports_inline_contig_alloc", Boolean.class); - public final long heapEndAddress = getFieldValue("CompilerToVM::Data::_heap_end_addr", Long.class, "HeapWord**"); - public final long heapTopAddress = getFieldValue("CompilerToVM::Data::_heap_top_addr", Long.class, JDK <= 8 ? "HeapWord**" : "HeapWord* volatile*"); - - public final boolean cmsIncrementalMode = getFlag("CMSIncrementalMode", Boolean.class, false, JDK <= 8); - public final long inlineCacheMissStub = getFieldValue("CompilerToVM::Data::SharedRuntime_ic_miss_stub", Long.class, "address"); public final long handleWrongMethodStub = getFieldValue("CompilerToVM::Data::SharedRuntime_handle_wrong_method_stub", Long.class, "address"); @@ -868,24 +715,6 @@ private boolean checkNullAllocationStubs() { public final int jvmciCountersSize = getFlag("JVMCICounterSize", Integer.class); - public final long deoptimizationFetchUnrollInfo = getAddress("Deoptimization::fetch_unroll_info"); - public final long deoptimizationUncommonTrap = getAddress("Deoptimization::uncommon_trap"); - public final long deoptimizationUnpackFrames = getAddress("Deoptimization::unpack_frames"); - - public final int deoptimizationUnpackDeopt = getConstant("Deoptimization::Unpack_deopt", Integer.class); - public final int deoptimizationUnpackException = getConstant("Deoptimization::Unpack_exception", Integer.class); - public final int deoptimizationUnpackUncommonTrap = getConstant("Deoptimization::Unpack_uncommon_trap", Integer.class); - public final int deoptimizationUnpackReexecute = getConstant("Deoptimization::Unpack_reexecute", Integer.class); - - public final int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset = getFieldOffset("Deoptimization::UnrollBlock::_size_of_deoptimized_frame", Integer.class, "int"); - public final int deoptimizationUnrollBlockCallerAdjustmentOffset = getFieldOffset("Deoptimization::UnrollBlock::_caller_adjustment", Integer.class, "int"); - public final int deoptimizationUnrollBlockNumberOfFramesOffset = getFieldOffset("Deoptimization::UnrollBlock::_number_of_frames", Integer.class, "int"); - public final int deoptimizationUnrollBlockTotalFrameSizesOffset = getFieldOffset("Deoptimization::UnrollBlock::_total_frame_sizes", Integer.class, "int"); - public final int deoptimizationUnrollBlockUnpackKindOffset = getFieldOffset("Deoptimization::UnrollBlock::_unpack_kind", Integer.class, "int"); - public final int deoptimizationUnrollBlockFrameSizesOffset = getFieldOffset("Deoptimization::UnrollBlock::_frame_sizes", Integer.class, "intptr_t*"); - public final int deoptimizationUnrollBlockFramePcsOffset = getFieldOffset("Deoptimization::UnrollBlock::_frame_pcs", Integer.class, "address*"); - public final int deoptimizationUnrollBlockInitialInfoOffset = getFieldOffset("Deoptimization::UnrollBlock::_initial_info", Integer.class, "intptr_t"); - // JDK-8231756, GR-16685 public final boolean deoptimizationSupportLargeAccessByteArrayVirtualization = // getConstant("Deoptimization::_support_large_access_byte_array_virtualization", Boolean.class, false, JVMCI || JDK >= 15); diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java index 47aeb87f705c..7e644b843e7c 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java @@ -30,9 +30,9 @@ import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallDescriptor.Transition.LEAF_NO_VZERO; import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallDescriptor.Transition.SAFEPOINT; import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.NO_LOCATIONS; +import static org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider.UNSAFE_ARRAYCOPY; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_END_LOCATION; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_TOP_LOCATION; -import static org.graalvm.compiler.replacements.arraycopy.ArrayCopyForeignCalls.UNSAFE_ARRAYCOPY; import static org.graalvm.word.LocationIdentity.any; import java.util.EnumSet; @@ -53,16 +53,12 @@ import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallDescriptor; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; import org.graalvm.compiler.hotspot.nodes.VMErrorNode; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantStubCall; -import org.graalvm.compiler.hotspot.replacements.AESCryptSubstitutions; import org.graalvm.compiler.hotspot.replacements.BigIntegerSubstitutions; -import org.graalvm.compiler.hotspot.replacements.CipherBlockChainingSubstitutions; import org.graalvm.compiler.hotspot.replacements.DigestBaseSubstitutions; import org.graalvm.compiler.hotspot.stubs.ExceptionHandlerStub; import org.graalvm.compiler.hotspot.stubs.Stub; import org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub; import org.graalvm.compiler.hotspot.word.KlassPointer; -import org.graalvm.compiler.hotspot.word.MethodCountersPointer; import org.graalvm.compiler.lir.LIR; import org.graalvm.compiler.lir.LIRFrameState; import org.graalvm.compiler.lir.LIRInstruction; @@ -151,42 +147,28 @@ public static class Options { private final HotSpotGraalRuntimeProvider runtime; /** - * @see AESCryptSubstitutions#encryptBlockStub(ForeignCallDescriptor, Word, Word, Pointer) + * @see org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins.AESCryptPlugin */ - public static final HotSpotForeignCallDescriptor ENCRYPT_BLOCK = new HotSpotForeignCallDescriptor(LEAF, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Byte), "encrypt_block", - void.class, Word.class, Word.class, Pointer.class); + public static final HotSpotForeignCallDescriptor AESCRYPT_ENCRYPTBLOCK = new HotSpotForeignCallDescriptor(LEAF, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Byte), + "aescrypt_encryptBlock", void.class, Word.class, Word.class, Pointer.class); /** - * @see AESCryptSubstitutions#decryptBlockStub(ForeignCallDescriptor, Word, Word, Pointer) + * @see org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins.AESCryptPlugin */ - public static final HotSpotForeignCallDescriptor DECRYPT_BLOCK = new HotSpotForeignCallDescriptor(LEAF, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Byte), "decrypt_block", - void.class, Word.class, Word.class, Pointer.class); + public static final HotSpotForeignCallDescriptor AESCRYPT_DECRYPTBLOCK = new HotSpotForeignCallDescriptor(LEAF, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Byte), + "aescrypt_decryptBlock", void.class, Word.class, Word.class, Pointer.class); /** - * @see AESCryptSubstitutions#decryptBlockStub(ForeignCallDescriptor, Word, Word, Pointer) + * @see org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins.CipherBlockChainingCryptPlugin */ - public static final HotSpotForeignCallDescriptor DECRYPT_BLOCK_WITH_ORIGINAL_KEY = new HotSpotForeignCallDescriptor(LEAF, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Byte), - "decrypt_block_with_original_key", void.class, Word.class, Word.class, Pointer.class, - Pointer.class); + public static final HotSpotForeignCallDescriptor CIPHER_BLOCK_CHAINING_ENCRYPT_AESCRYPT = new HotSpotForeignCallDescriptor(LEAF, NOT_REEXECUTABLE, + NamedLocationIdentity.getArrayLocation(JavaKind.Byte), "cipherBlockChaining_encrypt_aescrypt", int.class, Word.class, Word.class, Pointer.class, Pointer.class, int.class); /** - * @see CipherBlockChainingSubstitutions#crypt + * @see org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins.CipherBlockChainingCryptPlugin */ - public static final HotSpotForeignCallDescriptor ENCRYPT = new HotSpotForeignCallDescriptor(LEAF, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Byte), "encrypt", void.class, - Word.class, Word.class, Pointer.class, Pointer.class, int.class); - - /** - * @see CipherBlockChainingSubstitutions#crypt - */ - public static final HotSpotForeignCallDescriptor DECRYPT = new HotSpotForeignCallDescriptor(LEAF, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Byte), "decrypt", void.class, - Word.class, Word.class, Pointer.class, Pointer.class, int.class); - - /** - * @see CipherBlockChainingSubstitutions#crypt - */ - public static final HotSpotForeignCallDescriptor DECRYPT_WITH_ORIGINAL_KEY = new HotSpotForeignCallDescriptor(LEAF, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Byte), - "decrypt_with_original_key", void.class, Word.class, Word.class, Pointer.class, Pointer.class, - int.class, Pointer.class); + public static final HotSpotForeignCallDescriptor CIPHER_BLOCK_CHAINING_DECRYPT_AESCRYPT = new HotSpotForeignCallDescriptor(LEAF, NOT_REEXECUTABLE, + NamedLocationIdentity.getArrayLocation(JavaKind.Byte), "cipherBlockChaining_decrypt_aescrypt", int.class, Word.class, Word.class, Pointer.class, Pointer.class, int.class); /** * @see BigIntegerSubstitutions#multiplyToLen @@ -203,19 +185,16 @@ public static void multiplyToLenStub(Word xAddr, int xlen, Word yAddr, int ylen, private static native void multiplyToLenStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word xIn, int xLen, Word yIn, int yLen, Word zIn, int zLen); public static final HotSpotForeignCallDescriptor MUL_ADD = new HotSpotForeignCallDescriptor(LEAF_NO_VZERO, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Int), "mulAdd", - int.class, - Word.class, Word.class, int.class, int.class, int.class); + int.class, Word.class, Word.class, int.class, int.class, int.class); public static final HotSpotForeignCallDescriptor MONTGOMERY_MULTIPLY = new HotSpotForeignCallDescriptor(LEAF_NO_VZERO, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Int), - "implMontgomeryMultiply", void.class, Word.class, Word.class, Word.class, int.class, long.class, - Word.class); + "implMontgomeryMultiply", void.class, Word.class, Word.class, Word.class, int.class, long.class, Word.class); public static final HotSpotForeignCallDescriptor MONTGOMERY_SQUARE = new HotSpotForeignCallDescriptor(LEAF_NO_VZERO, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Int), "implMontgomerySquare", void.class, Word.class, Word.class, int.class, long.class, Word.class); public static final HotSpotForeignCallDescriptor SQUARE_TO_LEN = new HotSpotForeignCallDescriptor(LEAF_NO_VZERO, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Int), - "implSquareToLen", - void.class, Word.class, int.class, Word.class, int.class); + "implSquareToLen", void.class, Word.class, int.class, Word.class, int.class); public static final HotSpotForeignCallDescriptor SHA_IMPL_COMPRESS = new HotSpotForeignCallDescriptor(LEAF, NOT_REEXECUTABLE, any(), "shaImplCompress", void.class, Word.class, Object.class); @@ -282,16 +261,7 @@ public static void unsafeArraycopy(Word srcAddr, Word dstAddr, Word size) { * Descriptor for {@code StubRoutines::_counterMode_AESCrypt}. */ public static final HotSpotForeignCallDescriptor COUNTERMODE_IMPL_CRYPT = new HotSpotForeignCallDescriptor(LEAF, NOT_REEXECUTABLE, any(), "counterModeAESCrypt", int.class, - Word.class, Word.class, Word.class, Word.class, int.class, - Word.class, Word.class); - - public static int counterModeAESCrypt(Word srcAddr, Word dstAddr, Word kPtr, Word cntPtr, int len, Word encCntPtr, Word used) { - return counterModeAESCrypt(COUNTERMODE_IMPL_CRYPT, srcAddr, dstAddr, kPtr, cntPtr, len, encCntPtr, used); - } - - @NodeIntrinsic(ForeignCallNode.class) - private static native int counterModeAESCrypt(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word srcAddr, Word dstAddr, Word kPtr, Word cntPtr, int len, Word encCntPtr, - Word used); + Word.class, Word.class, Word.class, Word.class, int.class, Word.class, Word.class); /** * Descriptor for {@code StubRoutines::_vectorizedMismatch}. @@ -352,45 +322,6 @@ private static native int counterModeAESCrypt(@ConstantNodeParameter ForeignCall public static final HotSpotForeignCallDescriptor NEW_INSTANCE_OR_NULL = new HotSpotForeignCallDescriptor(SAFEPOINT, REEXECUTABLE, TLAB_LOCATIONS, "new_instance_or_null", Object.class, KlassPointer.class); - /** - * @see ResolveConstantStubCall - */ - public static final HotSpotForeignCallDescriptor RESOLVE_STRING_BY_SYMBOL = new HotSpotForeignCallDescriptor(SAFEPOINT, REEXECUTABLE, TLAB_LOCATIONS, "resolve_string_by_symbol", Object.class, - Word.class, Word.class); - - /** - * @see ResolveConstantStubCall - */ - public static final HotSpotForeignCallDescriptor RESOLVE_DYNAMIC_INVOKE = new HotSpotForeignCallDescriptor(SAFEPOINT, REEXECUTABLE, any(), "resolve_dynamic_invoke", Object.class, Word.class); - - /** - * @see ResolveConstantStubCall - */ - public static final HotSpotForeignCallDescriptor RESOLVE_KLASS_BY_SYMBOL = new HotSpotForeignCallDescriptor(SAFEPOINT, REEXECUTABLE, any(), "resolve_klass_by_symbol", Word.class, Word.class, - Word.class); - - /** - * @see ResolveConstantStubCall - */ - public static final HotSpotForeignCallDescriptor INITIALIZE_KLASS_BY_SYMBOL = new HotSpotForeignCallDescriptor(SAFEPOINT, NOT_REEXECUTABLE, any(), "initialize_klass_by_symbol", Word.class, - Word.class, - Word.class); - - /** - * @see ResolveConstantStubCall - */ - public static final HotSpotForeignCallDescriptor RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS = new HotSpotForeignCallDescriptor(SAFEPOINT, REEXECUTABLE, NO_LOCATIONS, - "resolve_method_by_symbol_and_load_counters", Word.class, Word.class, Word.class, - Word.class); - - /** - * Tiered support. - */ - public static final HotSpotForeignCallDescriptor INVOCATION_EVENT = new HotSpotForeignCallDescriptor(SAFEPOINT, REEXECUTABLE, NO_LOCATIONS, "invocation_event", void.class, - MethodCountersPointer.class); - public static final HotSpotForeignCallDescriptor BACKEDGE_EVENT = new HotSpotForeignCallDescriptor(SAFEPOINT, REEXECUTABLE, NO_LOCATIONS, "backedge_event", void.class, MethodCountersPointer.class, - int.class, int.class); - public HotSpotBackend(HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { super(providers); this.runtime = runtime; diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java index d53f318a25a9..3a9d9fdf61bf 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java @@ -118,7 +118,7 @@ public static HotSpotCompiledCode createCompiledCode(CodeCacheProvider codeCache int totalFrameSize = compResult.getTotalFrameSize(); StackSlot customStackArea = compResult.getCustomStackArea(); - boolean isImmutablePIC = compResult.isImmutablePIC(); + boolean isImmutablePIC = false; // Legacy API from jaotc that no longer does anything if (method instanceof HotSpotResolvedJavaMethod) { HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method; diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java index ebab48d38cb5..89cd0225c089 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java @@ -26,7 +26,6 @@ import static jdk.vm.ci.common.InitTimer.timer; import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.core.common.GraalOptions.HotSpotPrintInlining; import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigAccess.JDK; @@ -163,7 +162,7 @@ public GlobalMetrics getMetricValues() { HotSpotGraalRuntime(String nameQualifier, HotSpotJVMCIRuntime jvmciRuntime, CompilerConfigurationFactory compilerConfigurationFactory, OptionValues initialOptions) { this.runtimeName = getClass().getSimpleName() + ":" + nameQualifier; HotSpotVMConfigStore store = jvmciRuntime.getConfigStore(); - config = GeneratePIC.getValue(initialOptions) ? new AOTGraalHotSpotVMConfig(store) : new GraalHotSpotVMConfig(store); + config = new GraalHotSpotVMConfig(store); // Only set HotSpotPrintInlining if it still has its default value (false). if (GraalOptions.HotSpotPrintInlining.getValue(initialOptions) == false && config.printInlining) { diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java index dd8634bfaf05..dee520a5baee 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java @@ -24,26 +24,13 @@ */ package org.graalvm.compiler.hotspot; -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; -import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode; -import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode; -import org.graalvm.compiler.hotspot.nodes.profiling.RandomSeedNode; -import org.graalvm.compiler.hotspot.replacements.EncodedSymbolConstant; -import org.graalvm.compiler.lir.LIRFrameState; import org.graalvm.compiler.lir.VirtualStackSlot; import org.graalvm.compiler.lir.gen.LIRGenerator; import org.graalvm.compiler.lir.gen.LIRGeneratorTool; -import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; -import jdk.vm.ci.hotspot.HotSpotObjectConstant; -import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.DeoptimizationAction; import jdk.vm.ci.meta.DeoptimizationReason; -import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.Value; /** @@ -74,97 +61,6 @@ public interface HotSpotLIRGenerator extends LIRGeneratorTool { */ void emitDeoptimizeWithExceptionInCaller(Value exception); - /** - * Emits code for a {@link LoadConstantIndirectlyNode}. - * - * @param constant - * @return value of loaded address in register - */ - Value emitLoadObjectAddress(Constant constant); - - /** - * Emits code for a {@link LoadConstantIndirectlyNode}. - * - * @param constant original constant - * @param action action to perform on the metaspace object - * @return Value of loaded address in register - */ - Value emitLoadMetaspaceAddress(Constant constant, HotSpotConstantLoadAction action); - - /** - * Emits code for a {@link GraalHotSpotVMConfigNode}. - * - * @param markId id of the value to load - * @param kind type of the value to load - * @return value of loaded global in register - */ - Value emitLoadConfigValue(HotSpotMarkId markId, LIRKind kind); - - /** - * Emits code for a {@link ResolveConstantNode} to resolve a {@link HotSpotObjectConstant}. - * - * @param constant original constant - * @param constantDescription a description of the string that need to be materialized (and - * interned) as java.lang.String, generated with {@link EncodedSymbolConstant} - * @param frameState frame state for the runtime call - * @return the address of the requested constant. - */ - Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState); - - /** - * Emits code to resolve a dynamic constant. - * - * @param constant original constant - * @param frameState frame state for the runtime call - * @return the address of the requested constant. - */ - Value emitResolveDynamicInvoke(Constant constant, LIRFrameState frameState); - - /** - * Emits code for a {@link ResolveConstantNode} to resolve a {@link HotSpotMetaspaceConstant}. - * - * @param constant original constant - * @param constantDescription a symbolic description of the {@link HotSpotMetaspaceConstant} - * generated by {@link EncodedSymbolConstant} - * @param frameState frame state for the runtime call - * @return the address of the requested constant. - */ - Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState); - - /** - * Emits code for a {@link ResolveMethodAndLoadCountersNode} to resolve a - * {@link HotSpotMetaspaceConstant} that represents a {@link ResolvedJavaMethod} and return the - * corresponding MethodCounters object. - * - * @param method original constant - * @param klassHint a klass in which the method is declared - * @param methodDescription is symbolic description of the constant generated by - * {@link EncodedSymbolConstant} - * @param frameState frame state for the runtime call - * @return the address of the requested constant. - */ - Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState); - - /** - * Emits code for a {@link ResolveConstantNode} to resolve a klass - * {@link HotSpotMetaspaceConstant} and run static initializer. - * - * - * @param constant original constant - * @param constantDescription a symbolic description of the {@link HotSpotMetaspaceConstant} - * generated by {@link EncodedSymbolConstant} - * @param frameState frame state for the runtime call - * @return the address of the requested constant. - */ - Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState); - - /** - * Emits code for a {@link RandomSeedNode}. - * - * @return value of the counter - */ - Value emitRandomSeed(); - /** * Gets a stack slot for a lock at a given lock nesting depth. */ diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotMarkId.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotMarkId.java index 0be630905b4b..0319ebf3794e 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotMarkId.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotMarkId.java @@ -72,6 +72,10 @@ void setValue(Integer value) { this.value = value; } + public int getValue() { + return value; + } + @Override public String getName() { return name(); diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/SymbolicSnippetEncoder.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/SymbolicSnippetEncoder.java index 23cee691847c..1df3979889ed 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/SymbolicSnippetEncoder.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/SymbolicSnippetEncoder.java @@ -110,7 +110,9 @@ import org.graalvm.compiler.replacements.SnippetCounter; import org.graalvm.compiler.replacements.SnippetIntegerHistogram; import org.graalvm.compiler.replacements.SnippetTemplate; +import org.graalvm.compiler.replacements.classfile.ClassfileBytecode; +import jdk.vm.ci.code.Architecture; import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; import jdk.vm.ci.hotspot.HotSpotObjectConstant; @@ -428,11 +430,40 @@ private StructuredGraph buildGraph(ResolvedJavaMethod method, ResolvedJavaMethod } } + /** + * Helper class to provide more precise information about the source of an illegal object when + * encoding graphs. + */ + private static class CheckingGraphEncoder extends GraphEncoder { + CheckingGraphEncoder(Architecture architecture) { + super(architecture); + } + + @Override + protected void addObject(Object object) { + checkIllegalSnippetObjects(object); + super.addObject(object); + } + } + + /** + * Check for Objects which should never appear in an encoded snippet. + */ + private static void checkIllegalSnippetObjects(Object o) { + if (o instanceof HotSpotSignature || o instanceof ClassfileBytecode) { + throw new GraalError("Illegal object in encoded snippet: " + o); + } + } + @SuppressWarnings("try") private boolean verifySnippetEncodeDecode(DebugContext debug, ResolvedJavaMethod method, ResolvedJavaMethod original, String originalMethodString, Object[] args, boolean trackNodeSourcePosition, StructuredGraph graph) { // Verify the encoding and decoding process - EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, HotSpotJVMCIRuntime.runtime().getHostJVMCIBackend().getTarget().arch); + GraphEncoder encoder = new CheckingGraphEncoder(HotSpotJVMCIRuntime.runtime().getHostJVMCIBackend().getTarget().arch); + encoder.prepare(graph); + encoder.finishPrepare(); + int startOffset = encoder.encode(graph); + EncodedGraph encodedGraph = new EncodedGraph(encoder.getEncoding(), startOffset, encoder.getObjects(), encoder.getNodeClasses(), graph); HotSpotProviders originalProvider = snippetReplacements.getProviders(); @@ -750,6 +781,7 @@ SnippetReflectionProvider getSnippetReflection() { * convert the object or pass it through. */ private Object filterSnippetObject(DebugContext debug, Object o) { + checkIllegalSnippetObjects(o); if (o instanceof HotSpotResolvedJavaMethod) { return filterMethod(debug, (HotSpotResolvedJavaMethod) o); } else if (o instanceof HotSpotResolvedJavaField) { @@ -771,8 +803,6 @@ private Object filterSnippetObject(DebugContext debug, Object o) { return filterStampPair(debug, (StampPair) o); } else if (o instanceof ResolvedJavaMethodBytecode) { return filterBytecode(debug, (ResolvedJavaMethodBytecode) o); - } else if (o instanceof HotSpotSignature) { - throw new GraalError(o.toString()); } return o; } @@ -928,8 +958,7 @@ private static String compareGraphStrings(StructuredGraph expectedGraph, String } private static String getCanonicalGraphString(StructuredGraph graph, boolean excludeVirtual, boolean checkConstants) { - SchedulePhase schedule = new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST); - schedule.apply(graph); + SchedulePhase.runWithoutContextOptimizations(graph, SchedulePhase.SchedulingStrategy.EARLIEST); StructuredGraph.ScheduleResult scheduleResult = graph.getLastSchedule(); NodeMap canonicalId = graph.createNodeMap(); diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java index 60da73af6d40..70677179e236 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java @@ -26,7 +26,6 @@ import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; import static org.graalvm.compiler.core.common.GraalOptions.AlwaysInlineVTableStubs; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.core.common.GraalOptions.InlineVTableStubs; import static org.graalvm.compiler.core.common.GraalOptions.OmitHotExceptionStacktrace; import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.OSR_MIGRATION_END; @@ -48,7 +47,6 @@ import java.util.Map; import org.graalvm.compiler.core.common.CompressEncoding; -import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.core.common.spi.ForeignCallSignature; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; @@ -70,11 +68,6 @@ import org.graalvm.compiler.hotspot.nodes.HotSpotIndirectCallTargetNode; import org.graalvm.compiler.hotspot.nodes.KlassBeingInitializedCheckNode; import org.graalvm.compiler.hotspot.nodes.VMErrorNode; -import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode; -import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode; import org.graalvm.compiler.hotspot.nodes.type.HotSpotNarrowOopStamp; import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; import org.graalvm.compiler.hotspot.nodes.type.MethodPointerStamp; @@ -99,9 +92,7 @@ import org.graalvm.compiler.hotspot.replacements.StringToBytesSnippets; import org.graalvm.compiler.hotspot.replacements.UnsafeCopyMemoryNode; import org.graalvm.compiler.hotspot.replacements.UnsafeSnippets; -import org.graalvm.compiler.hotspot.replacements.aot.ResolveConstantSnippets; import org.graalvm.compiler.hotspot.replacements.arraycopy.HotSpotArraycopySnippets; -import org.graalvm.compiler.hotspot.replacements.profiling.ProfileSnippets; import org.graalvm.compiler.hotspot.stubs.ForeignCallSnippets; import org.graalvm.compiler.hotspot.word.KlassPointer; import org.graalvm.compiler.nodes.AbstractBeginNode; @@ -255,8 +246,6 @@ public interface Extensions { protected LogSnippets.Templates logSnippets; protected ArrayCopySnippets.Templates arraycopySnippets; protected StringToBytesSnippets.Templates stringToBytesSnippets; - protected ResolveConstantSnippets.Templates resolveConstantSnippets; - protected ProfileSnippets.Templates profileSnippets; protected ObjectSnippets.Templates objectSnippets; protected UnsafeSnippets.Templates unsafeSnippets; protected ObjectCloneSnippets.Templates objectCloneSnippets; @@ -309,7 +298,6 @@ public void initialize(OptionValues options, Iterable fact stringToBytesSnippets = new StringToBytesSnippets.Templates(options, factories, providers, target); identityHashCodeSnippets = new IdentityHashCodeSnippets.Templates(new HotSpotHashCodeSnippets(), options, factories, providers, target, HotSpotReplacementsUtil.MARK_WORD_LOCATION); isArraySnippets = new IsArraySnippets.Templates(new HotSpotIsArraySnippets(), options, factories, providers, target); - resolveConstantSnippets = new ResolveConstantSnippets.Templates(options, factories, providers, target); objectCloneSnippets = new ObjectCloneSnippets.Templates(options, factories, providers, target); foreignCallSnippets = new ForeignCallSnippets.Templates(options, factories, providers, target); registerFinalizerSnippets = new RegisterFinalizerSnippets.Templates(options, factories, providers, target); @@ -317,10 +305,6 @@ public void initialize(OptionValues options, Iterable fact objectSnippets = new ObjectSnippets.Templates(options, factories, providers, target); } unsafeSnippets = new UnsafeSnippets.Templates(options, factories, providers, target); - if (JavaVersionUtil.JAVA_SPEC >= 11 && GeneratePIC.getValue(options)) { - // AOT only introduced in JDK 9 - profileSnippets = new ProfileSnippets.Templates(options, factories, providers, target); - } initializeExtensions(options, factories, providers, config); } @@ -492,24 +476,6 @@ private boolean lowerWithoutDelegation(Node n, LoweringTool tool) { lowerHubGetClassNode((HubGetClassNode) n, tool); } else if (n instanceof KlassLayoutHelperNode) { lowerKlassLayoutHelperNode((KlassLayoutHelperNode) n, tool); - } else if (n instanceof ResolveDynamicConstantNode) { - if (graph.getGuardsStage().areFrameStatesAtDeopts()) { - resolveConstantSnippets.lower((ResolveDynamicConstantNode) n, tool); - } - } else if (n instanceof ResolveConstantNode) { - if (graph.getGuardsStage().areFrameStatesAtDeopts()) { - resolveConstantSnippets.lower((ResolveConstantNode) n, tool); - } - } else if (n instanceof ResolveMethodAndLoadCountersNode) { - if (graph.getGuardsStage().areFrameStatesAtDeopts()) { - resolveConstantSnippets.lower((ResolveMethodAndLoadCountersNode) n, tool); - } - } else if (n instanceof InitializeKlassNode) { - if (graph.getGuardsStage().areFrameStatesAtDeopts()) { - resolveConstantSnippets.lower((InitializeKlassNode) n, tool); - } - } else if (n instanceof ProfileNode) { - profileSnippets.lower((ProfileNode) n, tool); } else if (n instanceof KlassBeingInitializedCheckNode) { getAllocationSnippets().lower((KlassBeingInitializedCheckNode) n, tool); } else if (n instanceof FastNotifyNode) { @@ -581,7 +547,7 @@ private void lowerHubGetClassNode(HubGetClassNode n, LoweringTool tool) { ValueNode hub = n.getHub(); GraalHotSpotVMConfig vmConfig = runtime.getVMConfig(); StructuredGraph graph = n.graph(); - assert !hub.isConstant() || GraalOptions.ImmutableCode.getValue(graph.getOptions()); + assert !hub.isConstant(); AddressNode mirrorAddress = createOffsetAddress(graph, hub, vmConfig.classMirrorOffset); FloatingReadNode read = graph.unique( new FloatingReadNode(mirrorAddress, CLASS_MIRROR_LOCATION, null, vmConfig.classMirrorIsHandle ? StampFactory.forKind(target.wordJavaKind) : n.stamp(NodeView.DEFAULT), @@ -615,7 +581,7 @@ private void lowerInvoke(Invoke invoke, LoweringTool tool, StructuredGraph graph if (!callTarget.isStatic()) { assert receiver != null : "non-static call must have a receiver"; if (receiver.stamp(NodeView.DEFAULT) instanceof ObjectStamp && !StampTool.isPointerNonNull(receiver)) { - ValueNode nonNullReceiver = createNullCheckedValue(receiver, invoke.asNode(), tool); + ValueNode nonNullReceiver = createNullCheckedValue(receiver, invoke.asFixedNode(), tool); parameters.set(0, nonNullReceiver); receiver = nonNullReceiver; } @@ -643,7 +609,7 @@ private void lowerInvoke(Invoke invoke, LoweringTool tool, StructuredGraph graph signature, callTarget.targetMethod(), HotSpotCallingConventionType.JavaCall, callTarget.invokeKind())); - graph.addBeforeFixed(invoke.asNode(), metaspaceMethod); + graph.addBeforeFixed(invoke.asFixedNode(), metaspaceMethod); graph.addAfterFixed(metaspaceMethod, compiledEntry); } } @@ -794,6 +760,7 @@ static final class Exceptions { cachedExceptions.put(BytecodeExceptionKind.OUT_OF_BOUNDS, clearStackTrace(new ArrayIndexOutOfBoundsException())); cachedExceptions.put(BytecodeExceptionKind.CLASS_CAST, clearStackTrace(new ClassCastException())); cachedExceptions.put(BytecodeExceptionKind.ARRAY_STORE, clearStackTrace(new ArrayStoreException())); + cachedExceptions.put(BytecodeExceptionKind.NEGATIVE_ARRAY_SIZE, clearStackTrace(new NegativeArraySizeException())); cachedExceptions.put(BytecodeExceptionKind.DIVISION_BY_ZERO, clearStackTrace(new ArithmeticException())); cachedExceptions.put(BytecodeExceptionKind.ILLEGAL_ARGUMENT_EXCEPTION_ARGUMENT_IS_NOT_AN_ARRAY, clearStackTrace(new IllegalArgumentException(BytecodeExceptionKind.ILLEGAL_ARGUMENT_EXCEPTION_ARGUMENT_IS_NOT_AN_ARRAY.getExceptionMessage()))); @@ -814,6 +781,7 @@ public static final class RuntimeCalls { runtimeCalls.put(BytecodeExceptionKind.CLASS_CAST, new ForeignCallSignature("createClassCastException", ClassCastException.class, Object.class, KlassPointer.class)); runtimeCalls.put(BytecodeExceptionKind.NULL_POINTER, new ForeignCallSignature("createNullPointerException", NullPointerException.class)); runtimeCalls.put(BytecodeExceptionKind.OUT_OF_BOUNDS, new ForeignCallSignature("createOutOfBoundsException", ArrayIndexOutOfBoundsException.class, int.class, int.class)); + runtimeCalls.put(BytecodeExceptionKind.NEGATIVE_ARRAY_SIZE, new ForeignCallSignature("createNegativeArraySizeException", NegativeArraySizeException.class, int.class)); runtimeCalls.put(BytecodeExceptionKind.DIVISION_BY_ZERO, new ForeignCallSignature("createDivisionByZeroException", ArithmeticException.class)); runtimeCalls.put(BytecodeExceptionKind.INTEGER_EXACT_OVERFLOW, new ForeignCallSignature("createIntegerExactOverflowException", ArithmeticException.class)); runtimeCalls.put(BytecodeExceptionKind.LONG_EXACT_OVERFLOW, new ForeignCallSignature("createLongExactOverflowException", ArithmeticException.class)); diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotAOTClassInitializationPlugin.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotAOTClassInitializationPlugin.java deleted file mode 100644 index 62fb99d5f869..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotAOTClassInitializationPlugin.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.meta; - -import java.util.function.Supplier; - -import org.graalvm.compiler.core.common.type.ObjectStamp; -import org.graalvm.compiler.core.common.type.Stamp; -import org.graalvm.compiler.core.common.type.StampFactory; -import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode; -import org.graalvm.compiler.nodes.FrameState; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.graphbuilderconf.ClassInitializationPlugin; -import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; - -import jdk.vm.ci.hotspot.HotSpotConstantPool; -import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; -import jdk.vm.ci.meta.ConstantPool; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; - -public final class HotSpotAOTClassInitializationPlugin implements ClassInitializationPlugin { - private static boolean shouldApply(GraphBuilderContext builder, ResolvedJavaType type) { - if (!builder.parsingIntrinsic()) { - if (!type.isArray()) { - ResolvedJavaMethod method = builder.getGraph().method(); - ResolvedJavaType methodHolder = method.getDeclaringClass(); - // We can elide initialization nodes if type >=: methodHolder. - // The type is already initialized by either "new" or "invokestatic". - - // Emit initialization node if type is an interface since: - // JLS 12.4: Before a class is initialized, its direct superclass must be - // initialized, but interfaces implemented by the class are not - // initialized and a class or interface type T will be initialized - // immediately before the first occurrence of accesses listed - // in JLS 12.4.1. - - return !type.isAssignableFrom(methodHolder) || type.isInterface(); - } else if (!type.getComponentType().isPrimitive()) { - // Always apply to object array types - return true; - } - } - return false; - } - - @Override - public boolean apply(GraphBuilderContext builder, ResolvedJavaType type, Supplier frameState, ValueNode[] classInit) { - if (shouldApply(builder, type)) { - Stamp hubStamp = builder.getStampProvider().createHubStamp((ObjectStamp) StampFactory.objectNonNull()); - ConstantNode hub = builder.append(ConstantNode.forConstant(hubStamp, ((HotSpotResolvedObjectType) type).klass(), builder.getMetaAccess(), builder.getGraph())); - DeoptimizingFixedWithNextNode result = builder.append(type.isArray() ? new ResolveConstantNode(hub) : new InitializeKlassNode(hub)); - result.setStateBefore(frameState.get()); - if (classInit != null) { - classInit[0] = result; - } - return true; - } - return false; - } - - @Override - public boolean supportsLazyInitialization(ConstantPool cp) { - return true; - } - - @Override - public void loadReferencedType(GraphBuilderContext builder, ConstantPool cp, int cpi, int opcode) { - ((HotSpotConstantPool) cp).loadReferencedType(cpi, opcode, false); - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotAOTProfilingPlugin.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotAOTProfilingPlugin.java deleted file mode 100644 index ca67f1030e3f..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotAOTProfilingPlugin.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.meta; - -import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; -import org.graalvm.compiler.options.Option; -import org.graalvm.compiler.options.OptionKey; -import org.graalvm.compiler.options.OptionType; -import org.graalvm.compiler.options.OptionValues; - -import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; -import jdk.vm.ci.meta.ResolvedJavaMethod; - -public class HotSpotAOTProfilingPlugin extends HotSpotProfilingPlugin { - public static class Options { - @Option(help = "Do profiling and callbacks to tiered runtime", type = OptionType.User)// - public static final OptionKey TieredAOT = new OptionKey<>(false); - @Option(help = "Invocation notification frequency", type = OptionType.Expert)// - public static final OptionKey TierAInvokeNotifyFreqLog = new OptionKey<>(13); - @Option(help = "Inlinee invocation notification frequency (-1 means count, but do not notify)", type = OptionType.Expert)// - public static final OptionKey TierAInvokeInlineeNotifyFreqLog = new OptionKey<>(-1); - @Option(help = "Invocation profile probability", type = OptionType.Expert)// - public static final OptionKey TierAInvokeProfileProbabilityLog = new OptionKey<>(8); - @Option(help = "Backedge notification frequency", type = OptionType.Expert)// - public static final OptionKey TierABackedgeNotifyFreqLog = new OptionKey<>(16); - @Option(help = "Backedge profile probability", type = OptionType.Expert)// - public static final OptionKey TierABackedgeProfileProbabilityLog = new OptionKey<>(12); - } - - @Override - public boolean shouldProfile(GraphBuilderContext builder, ResolvedJavaMethod method) { - return super.shouldProfile(builder, method) && ((HotSpotResolvedObjectType) method.getDeclaringClass()).getFingerprint() != 0; - } - - @Override - public int invokeNotifyFreqLog(OptionValues options) { - return Options.TierAInvokeNotifyFreqLog.getValue(options); - } - - @Override - public int invokeInlineeNotifyFreqLog(OptionValues options) { - return Options.TierAInvokeInlineeNotifyFreqLog.getValue(options); - } - - @Override - public int invokeProfilePobabilityLog(OptionValues options) { - return Options.TierAInvokeProfileProbabilityLog.getValue(options); - } - - @Override - public int backedgeNotifyFreqLog(OptionValues options) { - return Options.TierABackedgeNotifyFreqLog.getValue(options); - } - - @Override - public int backedgeProfilePobabilityLog(OptionValues options) { - return Options.TierABackedgeProfileProbabilityLog.getValue(options); - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraalConstantFieldProvider.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraalConstantFieldProvider.java index e004c7f96432..33c9e3e05153 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraalConstantFieldProvider.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraalConstantFieldProvider.java @@ -24,14 +24,6 @@ */ package org.graalvm.compiler.hotspot.meta; -import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE; -import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; -import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; - -import java.util.ArrayList; -import java.util.List; - -import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.options.OptionValues; @@ -55,54 +47,7 @@ public HotSpotGraalConstantFieldProvider(GraalHotSpotVMConfig config, MetaAccess @Override protected boolean isStaticFieldConstant(ResolvedJavaField field, OptionValues options) { - return super.isStaticFieldConstant(field, options) && (!ImmutableCode.getValue(options) || isEmbeddableField(field)); - } - - /** - * The set of fields whose values cannot be constant folded in ImmutableCode mode. This is - * volatile to support double-checked locking lazy initialization. - */ - private volatile List nonEmbeddableFields; - - protected boolean isEmbeddableField(ResolvedJavaField field) { - if (!IS_IN_NATIVE_IMAGE && (IS_BUILDING_NATIVE_IMAGE || nonEmbeddableFields == null)) { - synchronized (this) { - if (nonEmbeddableFields == null) { - List fields = new ArrayList<>(); - try { - fields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("TRUE"))); - fields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("FALSE"))); - - Class characterCacheClass = Character.class.getDeclaredClasses()[0]; - assert "java.lang.Character$CharacterCache".equals(characterCacheClass.getName()); - fields.add(metaAccess.lookupJavaField(characterCacheClass.getDeclaredField("cache"))); - - Class byteCacheClass = Byte.class.getDeclaredClasses()[0]; - assert "java.lang.Byte$ByteCache".equals(byteCacheClass.getName()); - fields.add(metaAccess.lookupJavaField(byteCacheClass.getDeclaredField("cache"))); - - Class shortCacheClass = Short.class.getDeclaredClasses()[0]; - assert "java.lang.Short$ShortCache".equals(shortCacheClass.getName()); - fields.add(metaAccess.lookupJavaField(shortCacheClass.getDeclaredField("cache"))); - - Class integerCacheClass = Integer.class.getDeclaredClasses()[0]; - assert "java.lang.Integer$IntegerCache".equals(integerCacheClass.getName()); - fields.add(metaAccess.lookupJavaField(integerCacheClass.getDeclaredField("cache"))); - - Class longCacheClass = Long.class.getDeclaredClasses()[0]; - assert "java.lang.Long$LongCache".equals(longCacheClass.getName()); - fields.add(metaAccess.lookupJavaField(longCacheClass.getDeclaredField("cache"))); - - fields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("UNASSIGNED_STACK"))); - fields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("SUPPRESSED_SENTINEL"))); - } catch (SecurityException | NoSuchFieldException e) { - throw new GraalError(e); - } - nonEmbeddableFields = fields; - } - } - } - return !nonEmbeddableFields.contains(field); + return super.isStaticFieldConstant(field, options); } @Override diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java index 9e77ca3fc861..3b61b146b461 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java @@ -25,16 +25,21 @@ package org.graalvm.compiler.hotspot.meta; import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.core.common.calc.Condition.EQ; +import static org.graalvm.compiler.core.common.calc.Condition.LT; +import static org.graalvm.compiler.core.common.calc.Condition.NE; import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigAccess.JDK; +import static org.graalvm.compiler.hotspot.HotSpotBackend.AESCRYPT_DECRYPTBLOCK; +import static org.graalvm.compiler.hotspot.HotSpotBackend.AESCRYPT_ENCRYPTBLOCK; import static org.graalvm.compiler.hotspot.HotSpotBackend.BASE64_ENCODE_BLOCK; +import static org.graalvm.compiler.hotspot.HotSpotBackend.CIPHER_BLOCK_CHAINING_DECRYPT_AESCRYPT; +import static org.graalvm.compiler.hotspot.HotSpotBackend.CIPHER_BLOCK_CHAINING_ENCRYPT_AESCRYPT; +import static org.graalvm.compiler.hotspot.HotSpotBackend.COUNTERMODE_IMPL_CRYPT; import static org.graalvm.compiler.hotspot.HotSpotBackend.CRC_TABLE_LOCATION; import static org.graalvm.compiler.hotspot.HotSpotBackend.GHASH_PROCESS_BLOCKS; import static org.graalvm.compiler.hotspot.HotSpotBackend.UPDATE_BYTES_CRC32; import static org.graalvm.compiler.hotspot.HotSpotBackend.UPDATE_BYTES_CRC32C; -import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HOTSPOT_OOP_HANDLE_LOCATION; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION; +import static org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins.AESCryptPlugin.AES_BLOCK_SIZE_IN_BYTES; import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing; import static org.graalvm.compiler.nodes.ConstantNode.forBoolean; @@ -44,49 +49,40 @@ import java.lang.ref.PhantomReference; import java.lang.ref.Reference; import java.lang.reflect.Array; -import java.lang.reflect.Type; +import java.lang.reflect.Modifier; import java.math.BigInteger; import java.util.zip.CRC32; import org.graalvm.collections.Pair; +import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; -import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.TypeReference; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.HotSpotBackend; import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; -import org.graalvm.compiler.hotspot.HotSpotMarkId; import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode; -import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode; import org.graalvm.compiler.hotspot.nodes.HotSpotLoadReservedReferenceNode; import org.graalvm.compiler.hotspot.nodes.HotSpotStoreReservedReferenceNode; -import org.graalvm.compiler.hotspot.replacements.AESCryptSubstitutions; import org.graalvm.compiler.hotspot.replacements.BigIntegerSubstitutions; import org.graalvm.compiler.hotspot.replacements.CallSiteTargetNode; -import org.graalvm.compiler.hotspot.replacements.CipherBlockChainingSubstitutions; -import org.graalvm.compiler.hotspot.replacements.ClassGetHubNode; -import org.graalvm.compiler.hotspot.replacements.CounterModeSubstitutions; import org.graalvm.compiler.hotspot.replacements.DigestBaseSubstitutions; import org.graalvm.compiler.hotspot.replacements.FastNotifyNode; -import org.graalvm.compiler.hotspot.replacements.HotSpotArraySubstitutions; -import org.graalvm.compiler.hotspot.replacements.HotSpotClassSubstitutions; import org.graalvm.compiler.hotspot.replacements.HotSpotIdentityHashCodeNode; +import org.graalvm.compiler.hotspot.replacements.HotSpotInvocationPluginHelper; import org.graalvm.compiler.hotspot.replacements.HotSpotReflectionGetCallerClassNode; import org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil; +import org.graalvm.compiler.hotspot.replacements.HubGetClassNode; import org.graalvm.compiler.hotspot.replacements.ObjectCloneNode; -import org.graalvm.compiler.hotspot.replacements.ReflectionSubstitutions; -import org.graalvm.compiler.hotspot.replacements.ThreadSubstitutions; import org.graalvm.compiler.hotspot.replacements.UnsafeCopyMemoryNode; import org.graalvm.compiler.hotspot.word.HotSpotWordTypes; import org.graalvm.compiler.nodes.ComputeObjectAddressNode; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.FieldLocationIdentity; -import org.graalvm.compiler.nodes.FixedGuardNode; import org.graalvm.compiler.nodes.LogicNode; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.PiNode; @@ -94,17 +90,16 @@ import org.graalvm.compiler.nodes.calc.AddNode; import org.graalvm.compiler.nodes.calc.AndNode; import org.graalvm.compiler.nodes.calc.ConditionalNode; -import org.graalvm.compiler.nodes.calc.IntegerEqualsNode; -import org.graalvm.compiler.nodes.calc.IntegerLessThanNode; +import org.graalvm.compiler.nodes.calc.IntegerTestNode; import org.graalvm.compiler.nodes.calc.IsNullNode; import org.graalvm.compiler.nodes.calc.LeftShiftNode; import org.graalvm.compiler.nodes.calc.ObjectEqualsNode; -import org.graalvm.compiler.nodes.calc.RightShiftNode; import org.graalvm.compiler.nodes.calc.SignExtendNode; import org.graalvm.compiler.nodes.calc.SubNode; import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode; import org.graalvm.compiler.nodes.calc.XorNode; import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.nodes.extended.GuardingNode; import org.graalvm.compiler.nodes.extended.JavaReadNode; import org.graalvm.compiler.nodes.extended.RawLoadNode; import org.graalvm.compiler.nodes.graphbuilderconf.ForeignCallPlugin; @@ -116,11 +111,12 @@ import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; import org.graalvm.compiler.nodes.java.ArrayLengthNode; +import org.graalvm.compiler.nodes.java.DynamicNewArrayNode; import org.graalvm.compiler.nodes.java.DynamicNewInstanceNode; +import org.graalvm.compiler.nodes.java.InstanceOfNode; import org.graalvm.compiler.nodes.java.NewArrayNode; import org.graalvm.compiler.nodes.java.ValidateNewInstanceClassNode; import org.graalvm.compiler.nodes.memory.OnHeapMemoryAccess.BarrierType; -import org.graalvm.compiler.nodes.memory.ReadNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; import org.graalvm.compiler.nodes.spi.Replacements; @@ -128,6 +124,7 @@ import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.tiers.CompilerConfiguration; import org.graalvm.compiler.replacements.InlineDuringParsingPlugin; +import org.graalvm.compiler.replacements.InvocationPluginHelper; import org.graalvm.compiler.replacements.MethodHandlePlugin; import org.graalvm.compiler.replacements.NodeIntrinsificationProvider; import org.graalvm.compiler.replacements.ReplacementsImpl; @@ -145,10 +142,12 @@ import jdk.vm.ci.hotspot.VMIntrinsicMethod; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.DeoptimizationAction; -import jdk.vm.ci.meta.DeoptimizationReason; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.UnresolvedJavaType; import jdk.vm.ci.services.Services; import sun.misc.Unsafe; @@ -159,12 +158,6 @@ public class HotSpotGraphBuilderPlugins { /** * Creates a {@link Plugins} object that should be used when running on HotSpot. - * - * @param constantReflection - * @param snippetReflection - * @param foreignCalls - * @param options - * @param target */ public static Plugins create(HotSpotGraalRuntimeProvider graalRuntime, CompilerConfiguration compilerConfiguration, @@ -189,37 +182,26 @@ public static Plugins create(HotSpotGraalRuntimeProvider graalRuntime, plugins.appendTypePlugin(nodePlugin); plugins.appendNodePlugin(nodePlugin); } - if (!GeneratePIC.getValue(options)) { - plugins.appendNodePlugin(new MethodHandlePlugin(constantReflection.getMethodHandleAccess(), !config.supportsMethodHandleDeoptimizationEntry())); - } + plugins.appendNodePlugin(new MethodHandlePlugin(constantReflection.getMethodHandleAccess(), !config.supportsMethodHandleDeoptimizationEntry())); plugins.appendInlineInvokePlugin(replacements); if (InlineDuringParsing.getValue(options)) { plugins.appendInlineInvokePlugin(new InlineDuringParsingPlugin()); } - if (GeneratePIC.getValue(options)) { - plugins.setClassInitializationPlugin(new HotSpotAOTClassInitializationPlugin()); - if (TieredAOT.getValue(options)) { - plugins.setProfilingPlugin(new HotSpotAOTProfilingPlugin()); - } - } else { - if (config.instanceKlassInitThreadOffset != -1) { - plugins.setClassInitializationPlugin(new HotSpotJITClassInitializationPlugin()); - } + if (config.instanceKlassInitThreadOffset != -1) { + plugins.setClassInitializationPlugin(new HotSpotJITClassInitializationPlugin()); } invocationPlugins.defer(new Runnable() { @Override public void run() { - registerObjectPlugins(invocationPlugins, options, config, replacements); + registerObjectPlugins(invocationPlugins, config, replacements); registerClassPlugins(plugins, config, replacements); registerSystemPlugins(invocationPlugins); - registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config, replacements); - if (!GeneratePIC.getValue(options)) { - registerCallSitePlugins(invocationPlugins); - } - registerReflectionPlugins(invocationPlugins, replacements); + registerThreadPlugins(invocationPlugins, config, replacements); + registerCallSitePlugins(invocationPlugins); + registerReflectionPlugins(invocationPlugins, replacements, config); registerAESPlugins(invocationPlugins, config, replacements); registerCRC32Plugins(invocationPlugins, config, replacements); registerCRC32CPlugins(invocationPlugins, config, replacements); @@ -230,7 +212,7 @@ public void run() { registerBase64Plugins(invocationPlugins, config, metaAccess); registerUnsafePlugins(invocationPlugins, config, replacements); StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, snippetReflection, invocationPlugins, replacements, true, false, true, graalRuntime.getHostProviders().getLowerer()); - registerArrayPlugins(invocationPlugins, replacements); + registerArrayPlugins(invocationPlugins, replacements, config); registerStringPlugins(invocationPlugins, replacements, wordTypes, foreignCalls, config); registerArraysSupportPlugins(invocationPlugins, config, replacements); registerReferencePlugins(invocationPlugins, replacements); @@ -242,15 +224,9 @@ public void run() { // In libgraal all NodeIntrinsics been converted into special nodes so the plugins // aren't needed. NodeIntrinsificationProvider nodeIntrinsificationProvider = new NodeIntrinsificationProvider(metaAccess, snippetReflection, foreignCalls, wordTypes, target); - invocationPlugins.defer(new Runnable() { - - @Override - public void run() { - - for (GeneratedPluginFactory factory : GraalServices.load(GeneratedPluginFactory.class)) { - factory.registerPlugins(invocationPlugins, nodeIntrinsificationProvider); - } - + invocationPlugins.defer(() -> { + for (GeneratedPluginFactory factory : GraalServices.load(GeneratedPluginFactory.class)) { + factory.registerPlugins(invocationPlugins, nodeIntrinsificationProvider); } }); } @@ -287,29 +263,21 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec } - private static void registerObjectPlugins(InvocationPlugins plugins, OptionValues options, GraalHotSpotVMConfig config, Replacements replacements) { + private static void registerObjectPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) { Registration r = new Registration(plugins, Object.class, replacements); - if (!GeneratePIC.getValue(options)) { - // FIXME: clone() requires speculation and requires a fix in here (to check that - // b.getAssumptions() != null), and in ReplacementImpl.getSubstitution() where there is - // an instantiation of IntrinsicGraphBuilder using a constructor that sets - // AllowAssumptions to YES automatically. The former has to inherit the assumptions - // settings from the root compile instead. So, for now, I'm disabling it for - // GeneratePIC. - r.register1("clone", Receiver.class, new InvocationPlugin() { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { - ValueNode object = receiver.get(); - b.addPush(JavaKind.Object, new ObjectCloneNode(MacroParams.of(b, targetMethod, object))); - return true; - } + r.register1("clone", Receiver.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + ValueNode object = receiver.get(); + b.addPush(JavaKind.Object, new ObjectCloneNode(MacroParams.of(b, targetMethod, object))); + return true; + } - @Override - public boolean inlineOnly() { - return true; - } - }); - } + @Override + public boolean inlineOnly() { + return true; + } + }); r.register1("hashCode", Receiver.class, new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { @@ -358,25 +326,118 @@ public boolean inlineOnly() { private static void registerClassPlugins(Plugins plugins, GraalHotSpotVMConfig config, Replacements replacements) { Registration r = new Registration(plugins.getInvocationPlugins(), Class.class, replacements); - r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getModifiers", Receiver.class); - r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isInterface", Receiver.class); + r.register1("getModifiers", Receiver.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { + ValueNode klass = helper.readKlassFromClass(receiver.get()); + // Primitive Class case + ValueNode nonNullKlass = helper.emitNullReturnGuard(klass, ConstantNode.forInt(Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC), GraalDirectives.UNLIKELY_PROBABILITY); + // other return Klass::_modifier_flags + helper.emitFinalReturn(JavaKind.Int, helper.readKlassModifierFlags(nonNullKlass)); + } + return true; + } + }); + r.register1("isInterface", Receiver.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { + ValueNode klass = helper.readKlassFromClass(receiver.get()); + // Primitive Class case returns false + ValueNode klassNonNull = helper.emitNullReturnGuard(klass, ConstantNode.forBoolean(false), GraalDirectives.UNLIKELY_PROBABILITY); + ValueNode accessFlags = helper.readKlassAccessFlags(klassNonNull); + // return (Klass::_access_flags & Modifier.INTERFACE) == 0 ? false : true + LogicNode test = IntegerTestNode.create(accessFlags, ConstantNode.forInt(Modifier.INTERFACE), NodeView.DEFAULT); + helper.emitFinalReturn(JavaKind.Boolean, ConditionalNode.create(test, ConstantNode.forBoolean(false), ConstantNode.forBoolean(true), NodeView.DEFAULT)); + } + return true; + } + }); r.register1("isPrimitive", Receiver.class, new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { - ValueNode hub = b.add(new ClassGetHubNode(receiver.get())); - LogicNode isNull = b.add(IsNullNode.create(hub)); - b.addPush(JavaKind.Boolean, ConditionalNode.create(isNull, b.add(forBoolean(true)), b.add(forBoolean(false)), NodeView.DEFAULT)); + try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { + ValueNode klass = helper.readKlassFromClass(receiver.get()); + LogicNode isNull = b.add(IsNullNode.create(klass)); + b.addPush(JavaKind.Boolean, ConditionalNode.create(isNull, b.add(forBoolean(true)), b.add(forBoolean(false)), NodeView.DEFAULT)); + } + return true; + } + }); + r.register1("getSuperclass", Receiver.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { + ValueNode klass = helper.readKlassFromClass(receiver.get()); + ConstantNode nullValue = ConstantNode.defaultForKind(JavaKind.Object); + + // Primitive Class case returns null + PiNode klassNonNull = helper.emitNullReturnGuard(klass, nullValue, GraalDirectives.UNLIKELY_PROBABILITY); + + // if ((Klass::_access_flags & Modifer.INTERCAE) != 0) return null + ValueNode accessFlags = helper.readKlassAccessFlags(klassNonNull); + LogicNode test = IntegerTestNode.create(accessFlags, ConstantNode.forInt(Modifier.INTERFACE), NodeView.DEFAULT); + helper.emitReturnIfNot(test, nullValue, GraalDirectives.UNLIKELY_PROBABILITY); + + // Handle array Class case + // if (Klass::_layout_helper < 0) return Object.class + ValueNode layoutHelper = helper.klassLayoutHelper(klassNonNull); + ResolvedJavaType objectType = b.getMetaAccess().lookupJavaType(Object.class); + ValueNode objectClass = ConstantNode.forConstant(b.getConstantReflection().asJavaClass(objectType), b.getMetaAccess()); + helper.emitReturnIf(layoutHelper, Condition.LT, ConstantNode.forInt(config.klassLayoutHelperNeutralValue), objectClass, + GraalDirectives.UNLIKELY_PROBABILITY); + + // Read Klass::_super + ValueNode superKlass = helper.readKlassSuperKlass(klassNonNull); + // Return null if super is null + PiNode superKlassNonNull = helper.emitNullReturnGuard(superKlass, nullValue, GraalDirectives.UNLIKELY_PROBABILITY); + // Convert Klass to Class and return + helper.emitFinalReturn(JavaKind.Object, new HubGetClassNode(b.getMetaAccess(), superKlassNonNull)); + } return true; } }); - r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getSuperclass", Receiver.class); if (config.jvmAccIsHiddenClass != 0) { - r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isHidden", Receiver.class); + r.register1("isHidden", Receiver.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { + ValueNode klass = helper.readKlassFromClass(receiver.get()); + // Primitive Class case returns false + ValueNode nonNullKlass = helper.emitNullReturnGuard(klass, ConstantNode.forBoolean(false), GraalDirectives.UNLIKELY_PROBABILITY); + // return (Klass::_access_flags & jvmAccIsHiddenClass) == 0 ? false : true + ValueNode accessFlags = helper.readKlassAccessFlags(nonNullKlass); + LogicNode test = IntegerTestNode.create(accessFlags, ConstantNode.forInt(config.jvmAccIsHiddenClass), NodeView.DEFAULT); + helper.emitFinalReturn(JavaKind.Boolean, ConditionalNode.create(test, ConstantNode.forBoolean(false), ConstantNode.forBoolean(true), NodeView.DEFAULT)); + } + return true; + } + }); } if (config.getFieldOffset("ArrayKlass::_component_mirror", Integer.class, "oop", Integer.MAX_VALUE, JDK <= 8) != Integer.MAX_VALUE) { - r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getComponentType", Receiver.class); + r.register1("getComponentType", Receiver.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { + ValueNode klass = helper.readKlassFromClass(receiver.get()); + // Primitive Class case returns null + final ConstantNode nullValue = ConstantNode.defaultForKind(JavaKind.Object); + ValueNode klassNonNull = helper.emitNullReturnGuard(klass, nullValue, GraalDirectives.UNLIKELY_PROBABILITY); + // Non-array case + // if (Klass::_layout_helper >= 0) return null + ValueNode layoutHelper = helper.klassLayoutHelper(klassNonNull); + GuardingNode guard = helper.emitReturnIf(layoutHelper, Condition.GE, ConstantNode.forInt(config.klassLayoutHelperNeutralValue), nullValue, + GraalDirectives.UNLIKELY_PROBABILITY); + // Return ArrayKlass::_component_mirror + ValueNode componentMirror = helper.readArrayKlassComponentMirror(klassNonNull, guard); + helper.emitFinalReturn(JavaKind.Object, componentMirror); + } + return true; + } + }); } } @@ -404,7 +465,7 @@ public boolean inlineOnly() { plugins.register(plugin, VolatileCallSite.class, "getTarget", Receiver.class); } - private static void registerReflectionPlugins(InvocationPlugins plugins, Replacements replacements) { + private static void registerReflectionPlugins(InvocationPlugins plugins, Replacements replacements, GraalHotSpotVMConfig config) { Registration r = new Registration(plugins, reflectionClass, replacements); r.register0("getCallerClass", new InvocationPlugin() { @Override @@ -418,7 +479,20 @@ public boolean inlineOnly() { return true; } }); - r.registerMethodSubstitution(ReflectionSubstitutions.class, "getClassAccessFlags", Class.class); + r.register1("getClassAccessFlags", Class.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { + try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { + ValueNode klass = helper.readKlassFromClass(b.nullCheckedValue(arg)); + // Primitive Class case + ValueNode klassNonNull = helper.emitNullReturnGuard(klass, ConstantNode.forInt(Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC), GraalDirectives.UNLIKELY_PROBABILITY); + // Return (Klass::_access_flags & jvmAccWrittenFlags) + ValueNode accessFlags = helper.readKlassAccessFlags(klassNonNull); + helper.emitFinalReturn(JavaKind.Int, new AndNode(accessFlags, ConstantNode.forInt(config.jvmAccWrittenFlags))); + } + return true; + } + }); } private static void registerUnsafePlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) { @@ -486,10 +560,26 @@ public boolean inlineOnly() { }); } - private static void registerArrayPlugins(InvocationPlugins plugins, Replacements replacements) { + private static void registerArrayPlugins(InvocationPlugins plugins, Replacements replacements, GraalHotSpotVMConfig config) { Registration r = new Registration(plugins, Array.class, replacements); r.setAllowOverwrite(true); - r.registerMethodSubstitution(HotSpotArraySubstitutions.class, "newInstance", Class.class, int.class); + r.register2("newInstance", Class.class, int.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode componentType, ValueNode length) { + try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { + // If (componentType == null) then deopt + ValueNode nonNullComponentType = b.nullCheckedValue(componentType); + // Read Class.array_klass + ValueNode arrayClass = helper.loadArrayKlass(nonNullComponentType); + // Take the fallback path is the array klass is null + helper.doFallbackIf(IsNullNode.create(arrayClass), GraalDirectives.UNLIKELY_PROBABILITY); + // Otherwise perform the array allocation + helper.emitFinalReturn(JavaKind.Object, new DynamicNewArrayNode(nonNullComponentType, length, + true)); + } + return true; + } + }); } private static void registerStringPlugins(InvocationPlugins plugins, Replacements replacements, WordTypes wordTypes, ArrayCopyForeignCalls foreignCalls, GraalHotSpotVMConfig vmConfig) { @@ -500,19 +590,20 @@ private static void registerStringPlugins(InvocationPlugins plugins, Replacement @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value, ValueNode srcBegin, ValueNode length) { - PluginHelper helper = new PluginHelper(b, wordTypes); - helper.guard(srcBegin, Condition.LT, ConstantNode.forInt(0), DeoptimizationAction.None, DeoptimizationReason.BoundsCheckException); - helper.guard(length, Condition.LT, ConstantNode.forInt(0), DeoptimizationAction.None, DeoptimizationReason.BoundsCheckException); - helper.guard(length, Condition.GT, ConstantNode.forInt(MAX_LENGTH), DeoptimizationAction.None, DeoptimizationReason.BoundsCheckException); - ValueNode valueLength = b.add(new ArrayLengthNode(value)); - ValueNode limit = b.add(new SubNode(valueLength, length)); - helper.guard(srcBegin, Condition.GT, limit, DeoptimizationAction.None, DeoptimizationReason.BoundsCheckException); - ValueNode newArray = b.add(new NewArrayNode(b.getMetaAccess().lookupJavaType(Byte.TYPE), b.add(new LeftShiftNode(length, ConstantNode.forInt(1))), false)); - b.addPush(JavaKind.Object, newArray); - // The stateAfter should include the value pushed, so push it first and then - // perform the call that fills in the array. - b.add(new ArrayCopyCallNode(foreignCalls, wordTypes, value, srcBegin, newArray, ConstantNode.forInt(0), length, JavaKind.Char, LocationIdentity.init(), false, true, true, - vmConfig.heapWordSize)); + try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, vmConfig)) { + helper.intrinsicRangeCheck(srcBegin, Condition.LT, ConstantNode.forInt(0)); + helper.intrinsicRangeCheck(length, Condition.LT, ConstantNode.forInt(0)); + helper.intrinsicRangeCheck(length, Condition.GT, ConstantNode.forInt(MAX_LENGTH)); + ValueNode valueLength = b.add(new ArrayLengthNode(value)); + ValueNode limit = b.add(new SubNode(valueLength, length)); + helper.intrinsicRangeCheck(srcBegin, Condition.GT, limit); + ValueNode newArray = b.add(new NewArrayNode(b.getMetaAccess().lookupJavaType(Byte.TYPE), b.add(new LeftShiftNode(length, ConstantNode.forInt(1))), false)); + b.addPush(JavaKind.Object, newArray); + // The stateAfter should include the value pushed, so push it first and then + // perform the call that fills in the array. + b.add(new ArrayCopyCallNode(foreignCalls, wordTypes, value, srcBegin, newArray, ConstantNode.forInt(0), length, JavaKind.Char, LocationIdentity.init(), false, true, true, + vmConfig.heapWordSize)); + } return true; } }); @@ -520,41 +611,32 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value, ValueNode srcBegin, ValueNode srcEnd, ValueNode dst, ValueNode dstBegin) { - PluginHelper helper = new PluginHelper(b, wordTypes); - ValueNode length = helper.sub(srcEnd, srcBegin); - helper.guard(srcBegin, Condition.LT, ConstantNode.forInt(0), DeoptimizationAction.None, DeoptimizationReason.BoundsCheckException); - helper.guard(length, Condition.LT, ConstantNode.forInt(0), DeoptimizationAction.None, DeoptimizationReason.BoundsCheckException); - ValueNode srcLimit = helper.sub(helper.rightShift(helper.length(value), 1), length); - helper.guard(srcBegin, Condition.GT, srcLimit, DeoptimizationAction.None, DeoptimizationReason.BoundsCheckException); - ValueNode limit = helper.sub(helper.length(dst), length); - helper.guard(dstBegin, Condition.GT, limit, DeoptimizationAction.None, DeoptimizationReason.BoundsCheckException); - b.add(new ArrayCopyCallNode(foreignCalls, wordTypes, value, srcBegin, dst, dstBegin, length, JavaKind.Char, JavaKind.Byte, JavaKind.Char, false, true, true, - vmConfig.heapWordSize)); + try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, vmConfig)) { + ValueNode length = helper.sub(srcEnd, srcBegin); + helper.intrinsicRangeCheck(srcBegin, Condition.LT, ConstantNode.forInt(0)); + helper.intrinsicRangeCheck(length, Condition.LT, ConstantNode.forInt(0)); + ValueNode srcLimit = helper.sub(helper.shr(helper.length(value), 1), length); + helper.intrinsicRangeCheck(srcBegin, Condition.GT, srcLimit); + ValueNode limit = helper.sub(helper.length(dst), length); + helper.intrinsicRangeCheck(dstBegin, Condition.GT, limit); + b.add(new ArrayCopyCallNode(foreignCalls, wordTypes, value, srcBegin, dst, dstBegin, length, JavaKind.Char, JavaKind.Byte, JavaKind.Char, false, true, true, + vmConfig.heapWordSize)); + } return true; } }); } } - private static void registerThreadPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, WordTypes wordTypes, GraalHotSpotVMConfig config, Replacements replacements) { + private static void registerThreadPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) { Registration r = new Registration(plugins, Thread.class, replacements); r.register0("currentThread", new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { - CurrentJavaThreadNode thread = b.add(new CurrentJavaThreadNode(wordTypes.getWordKind())); - ValueNode offset = b.add(ConstantNode.forLong(config.threadObjectOffset)); - AddressNode address = b.add(new OffsetAddressNode(thread, offset)); - // JavaThread::_threadObj is never compressed - ObjectStamp stamp = StampFactory.objectNonNull(TypeReference.create(b.getAssumptions(), metaAccess.lookupJavaType(Thread.class))); - ReadNode value = b.add(new ReadNode(address, JAVA_THREAD_THREAD_OBJECT_LOCATION, - config.threadObjectFieldIsHandle ? StampFactory.forKind(wordTypes.getWordKind()) : stamp, BarrierType.NONE)); - if (config.threadObjectFieldIsHandle) { - // Read the Object from the OopHandle - ValueNode handleOffset = ConstantNode.forIntegerKind(wordTypes.getWordKind(), 0, b.getGraph()); - AddressNode handleAddress = b.add(new OffsetAddressNode(value, handleOffset)); - value = b.add(new ReadNode(handleAddress, HOTSPOT_OOP_HANDLE_LOCATION, stamp, BarrierType.NONE)); + try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { + ValueNode value = helper.readCurrentThreadObject(); + b.push(JavaKind.Object, value); } - b.push(JavaKind.Object, value); return true; } }); @@ -562,7 +644,32 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec if (config.osThreadInterruptedOffset != Integer.MAX_VALUE) { // This substitution is no longer in used when threadObj is a handle assert !config.threadObjectFieldIsHandle; - r.registerMethodSubstitution(ThreadSubstitutions.class, "isInterrupted", Receiver.class, boolean.class); + r.register2("isInterrupted", Receiver.class, boolean.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode clearInterrupted) { + try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { + ValueNode receiverThreadObject = receiver.get(); + CurrentJavaThreadNode thread = b.add(new CurrentJavaThreadNode(helper.getWordKind())); + ValueNode currentThreadObject = helper.readCurrentThreadObject(thread); + + // if (this != Thread.currentThread()) do fallback + helper.doFallbackIf(receiverThreadObject, NE, currentThreadObject, GraalDirectives.UNLIKELY_PROBABILITY); + ValueNode osThread = helper.readOsThread(thread); + ValueNode interrupted = helper.readOsThreadInterrupted(osThread); + + // if (thread._osthread._isinterrupted == 0) return false + helper.emitReturnIf(interrupted, EQ, ConstantNode.forInt(0), ConstantNode.forBoolean(false), GraalDirectives.LIKELY_PROBABILITY); + + // if (clearInterrupted) fallback to invoke + helper.doFallbackIf(clearInterrupted, EQ, ConstantNode.forBoolean(true), GraalDirectives.UNLIKELY_PROBABILITY); + + // return interrupted == 0 ? false : true + LogicNode test = helper.createCompare(interrupted, CanonicalCondition.EQ, ConstantNode.forInt(0)); + helper.emitFinalReturn(JavaKind.Boolean, ConditionalNode.create(test, ConstantNode.forBoolean(false), ConstantNode.forBoolean(true), NodeView.DEFAULT)); + } + return true; + } + }); } } @@ -616,176 +723,180 @@ public static boolean isIntrinsicName(GraalHotSpotVMConfig config, String classN return false; } - private static void registerAESPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) { - if (config.useAESIntrinsics) { - assert config.aescryptEncryptBlockStub != 0L; - assert config.aescryptDecryptBlockStub != 0L; - assert config.cipherBlockChainingEncryptAESCryptStub != 0L; - assert config.cipherBlockChainingDecryptAESCryptStub != 0L; - - Registration r = new Registration(plugins, "com.sun.crypto.provider.CipherBlockChaining", replacements); - - Pair cbcEncryptName = selectIntrinsicName(config, "com/sun/crypto/provider/CipherBlockChaining", "implEncrypt", "encrypt"); - registerAndCheckMismatch(r, CipherBlockChainingSubstitutions.class, cbcEncryptName, Receiver.class, byte[].class, int.class, int.class, - byte[].class, int.class); + // Fully qualified name is a workaround for JDK-8056066 + public static class AESCryptPlugin implements org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin { + private final boolean doEncrypt; - Pair cbcDecryptName = selectIntrinsicName(config, "com/sun/crypto/provider/CipherBlockChaining", "implDecrypt", "decrypt"); - registerAndCheckMismatch(r, CipherBlockChainingSubstitutions.class, cbcDecryptName, cbcDecryptName.getLeft(), Receiver.class, byte[].class, int.class, int.class, - byte[].class, int.class); - - r = new Registration(plugins, "com.sun.crypto.provider.AESCrypt", replacements); - - Pair aesEncryptName = selectIntrinsicName(config, "com/sun/crypto/provider/AESCrypt", "implEncryptBlock", "encryptBlock"); - registerAndCheckMismatch(r, AESCryptSubstitutions.class, aesEncryptName, Receiver.class, byte[].class, int.class, byte[].class, int.class); - - Pair aesDecryptName = selectIntrinsicName(config, "com/sun/crypto/provider/AESCrypt", "implDecryptBlock", "decryptBlock"); - registerAndCheckMismatch(r, AESCryptSubstitutions.class, aesDecryptName, aesDecryptName.getLeft(), Receiver.class, byte[].class, int.class, byte[].class, int.class); - } - } - - private static void registerAndCheckMismatch(Registration r, Class substitutionClass, Pair intrinsicNames, Type... argumentTypes) { - try { - r.registerMethodSubstitution(substitutionClass, intrinsicNames.getLeft(), argumentTypes); - } catch (NoSuchMethodError e) { - throw new GraalError(e, "Found method named '%s' instead of '%s' in class '%s'. This is most likely because the JVMCI JDK in %s was built on an incompatible base JDK.", - intrinsicNames.getRight(), intrinsicNames.getLeft(), r.getDeclaringType().getTypeName(), Services.getSavedProperties().get("java.home")); + public static ResolvedJavaType getType(ResolvedJavaType context, String typeName) { + try { + UnresolvedJavaType unresolved = UnresolvedJavaType.create(typeName); + return unresolved.resolve(context); + } catch (LinkageError e) { + throw new GraalError(e); + } } - } - private static void registerAndCheckMismatch(Registration r, Class substitutionClass, Pair intrinsicNames, String substituteName, Type... argumentTypes) { - try { - r.registerMethodSubstitution(substitutionClass, intrinsicNames.getLeft(), substituteName, argumentTypes); - } catch (NoSuchMethodError e) { - throw new GraalError(e, "Found method named '%s' instead of '%s' in class '%s'. This is most likely because the JVMCI JDK in %s was built on an incompatible base JDK.", - intrinsicNames.getRight(), intrinsicNames.getLeft(), r.getDeclaringType().getTypeName(), Services.getSavedProperties().get("java.home")); + static ResolvedJavaType aesCryptType(ResolvedJavaType context) { + return getType(context, "Lcom/sun/crypto/provider/AESCrypt;"); } - } - private static void registerAndCheckMismatch(Registration r, Pair intrinsicNames, Type arg1, Type arg2, Type arg3, InvocationPlugin plugin) { - try { - r.register3(intrinsicNames.getLeft(), arg1, arg2, arg3, plugin); - } catch (NoSuchMethodError e) { - throw new GraalError(e, "Found method named '%s' instead of '%s' in class '%s'. This is most likely because the JVMCI JDK in %s was built on an incompatible base JDK.", - intrinsicNames.getRight(), intrinsicNames.getLeft(), r.getDeclaringType().getTypeName(), Services.getSavedProperties().get("java.home")); + AESCryptPlugin(boolean doEncrypt) { + this.doEncrypt = doEncrypt; } - } - - private static ValueNode arrayStart(GraphBuilderContext b, ValueNode array, JavaKind kind) { - int byteArrayBaseOffset = b.getMetaAccess().getArrayBaseOffset(kind); - return b.add(new ComputeObjectAddressNode(array, ConstantNode.forInt(byteArrayBaseOffset))); - } - - private static ValueNode byteArrayStart(GraphBuilderContext b, ValueNode array) { - JavaKind kind = JavaKind.Byte; - return arrayStart(b, array, kind); - } - static class PluginHelper { - protected final GraphBuilderContext context; - protected final WordTypes wordTypes; + /** + * The AES block size is a constant 128 bits as defined by the + * standard. + */ + static final int AES_BLOCK_SIZE_IN_BYTES = 16; - PluginHelper(GraphBuilderContext context, WordTypes wordTypes) { - this.context = context; - this.wordTypes = wordTypes; + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode in, ValueNode inOffset, ValueNode out, ValueNode outOffset) { + try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) { + ValueNode nonNullReceiver = receiver.get(); + ValueNode nonNullIn = b.nullCheckedValue(in); + ValueNode nonNullOut = b.nullCheckedValue(out); + + ConstantNode zero = ConstantNode.forInt(0); + // if (inOffset < 0) then deopt + helper.intrinsicRangeCheck(inOffset, LT, zero); + // if (in.length - AES_BLOCK_SIZE_IN_BYTES < inOffset) then deopt + ValueNode inLength = helper.length(nonNullIn); + helper.intrinsicRangeCheck(helper.sub(inLength, ConstantNode.forInt(AES_BLOCK_SIZE_IN_BYTES)), LT, inOffset); + // if (outOffset < 0) then deopt + helper.intrinsicRangeCheck(outOffset, LT, zero); + // if (out.length - AES_BLOCK_SIZE_IN_BYTES < outOffset) then deopt + ValueNode outLength = helper.length(nonNullOut); + helper.intrinsicRangeCheck(helper.sub(outLength, ConstantNode.forInt(AES_BLOCK_SIZE_IN_BYTES)), LT, outOffset); + + // Read AESCrypt.K from receiver + ResolvedJavaField kField = helper.getField(aesCryptType(targetMethod.getDeclaringClass()), "K"); + ValueNode k = b.nullCheckedValue(helper.loadField(nonNullReceiver, kField)); + // Compute pointers to the array bodies + ValueNode kAddr = helper.arrayStart(k, JavaKind.Int); + ValueNode inAddr = helper.arrayElementPointer(nonNullIn, JavaKind.Byte, inOffset); + ValueNode outAddr = helper.arrayElementPointer(nonNullOut, JavaKind.Byte, outOffset); + HotSpotForeignCallDescriptor descriptor = doEncrypt ? AESCRYPT_ENCRYPTBLOCK : AESCRYPT_DECRYPTBLOCK; + b.add(new ForeignCallNode(descriptor, inAddr, outAddr, kAddr)); + } + return true; } + } - ValueNode xor(ValueNode x, ValueNode y) { - return context.add(new XorNode(x, y)); - } + public static class CipherBlockChainingCryptPlugin implements InvocationPlugin { + private final boolean doEncrypt; - ValueNode add(ValueNode x, ValueNode y) { - return context.add(new AddNode(x, y)); + public static ResolvedJavaType getType(ResolvedJavaType context, String typeName) { + try { + UnresolvedJavaType unresolved = UnresolvedJavaType.create(typeName); + return unresolved.resolve(context); + } catch (LinkageError e) { + throw new GraalError(e); + } } - ValueNode sub(ValueNode x, ValueNode y) { - return context.add(new SubNode(x, y)); + static ResolvedJavaType aesCryptType(ResolvedJavaType context) { + return getType(context, "Lcom/sun/crypto/provider/AESCrypt;"); } - ValueNode length(ValueNode x) { - return context.add(new ArrayLengthNode(x)); + static ResolvedJavaType feedbackCipherType(ResolvedJavaType context) { + return getType(context, "Lcom/sun/crypto/provider/FeedbackCipher;"); } - ValueNode byteArrayStart(ValueNode array) { - return arrayIndex(array, JavaKind.Byte, null); + CipherBlockChainingCryptPlugin(boolean doEncrypt) { + this.doEncrypt = doEncrypt; } - ValueNode arrayIndex(ValueNode array, JavaKind kind, ValueNode index) { - int arrayBaseOffset = context.getMetaAccess().getArrayBaseOffset(kind); - ValueNode offset = ConstantNode.forInt(arrayBaseOffset); - if (index != null) { - offset = add(offset, scale(index, kind)); + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode in, ValueNode inOffset, ValueNode inLength, ValueNode out, ValueNode outOffset) { + try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) { + ValueNode nonNullReceiver = receiver.get(); + // Read FeedbackCipher.embeddedCipher + ResolvedJavaField embeddedCipherField = helper.getField(feedbackCipherType(targetMethod.getDeclaringClass()), "embeddedCipher"); + ValueNode embeddedCipher = helper.loadField(nonNullReceiver, embeddedCipherField); + + // Use the fallback path if the embeddedCipher is not an instance of AESCrypt + LogicNode typeCheck = InstanceOfNode.create(TypeReference.create(b.getAssumptions(), aesCryptType(targetMethod.getDeclaringClass())), embeddedCipher); + helper.doFallbackIfNot(typeCheck, GraalDirectives.UNLIKELY_PROBABILITY); + + ValueNode nonNullIn = b.nullCheckedValue(in); + ValueNode nonNullOut = b.nullCheckedValue(out); + + ConstantNode zero = ConstantNode.forInt(0); + // if (inOffset < 0) then deopt + helper.intrinsicRangeCheck(inOffset, LT, zero); + // if (in.length - AES_BLOCK_SIZE_IN_BYTES < inOffset) then deopt + helper.intrinsicRangeCheck(helper.sub(inLength, ConstantNode.forInt(AES_BLOCK_SIZE_IN_BYTES)), LT, inOffset); + // if (outOffset < 0) then deopt + helper.intrinsicRangeCheck(outOffset, LT, zero); + // if (out.length - AES_BLOCK_SIZE_IN_BYTES < outOffset) then deopt + ValueNode outLength = helper.length(nonNullOut); + helper.intrinsicRangeCheck(helper.sub(outLength, ConstantNode.forInt(AES_BLOCK_SIZE_IN_BYTES)), LT, outOffset); + + // Read AESCrypt.K + ResolvedJavaField kField = helper.getField(aesCryptType(targetMethod.getDeclaringClass()), "K"); + ValueNode k = b.nullCheckedValue(helper.loadField(embeddedCipher, kField)); + + // Read CipherBlockChaining.r + ResolvedJavaField rField = helper.getField(targetMethod.getDeclaringClass(), "r"); + ValueNode r = b.nullCheckedValue(helper.loadField(nonNullReceiver, rField)); + + // Compute pointers into arrays + ValueNode kAddr = helper.arrayStart(k, JavaKind.Int); + ValueNode rAddr = helper.arrayStart(r, JavaKind.Byte); + ValueNode inAddr = helper.arrayElementPointer(nonNullIn, JavaKind.Byte, inOffset); + ValueNode outAddr = helper.arrayElementPointer(nonNullOut, JavaKind.Byte, outOffset); + HotSpotForeignCallDescriptor descriptor = doEncrypt ? CIPHER_BLOCK_CHAINING_ENCRYPT_AESCRYPT : CIPHER_BLOCK_CHAINING_DECRYPT_AESCRYPT; + ForeignCallNode call = b.add(new ForeignCallNode(descriptor, inAddr, outAddr, kAddr, rAddr, inLength)); + helper.emitFinalReturn(JavaKind.Int, call); } - - return context.add(new ComputeObjectAddressNode(array, offset)); + return true; } + } - private ValueNode scale(ValueNode index, JavaKind kind) { - int arrayIndexScale = context.getMetaAccess().getArrayIndexScale(kind); - return shl(asWord(index), arrayIndexScale); - } + private static void registerAESPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) { + if (config.useAESIntrinsics) { + assert config.aescryptEncryptBlockStub != 0L; + assert config.aescryptDecryptBlockStub != 0L; + assert config.cipherBlockChainingEncryptAESCryptStub != 0L; + assert config.cipherBlockChainingDecryptAESCryptStub != 0L; - private ValueNode shl(ValueNode node, int arrayIndexScale) { - if (arrayIndexScale == 1) { - return node; - } - return context.add(new LeftShiftNode(node, ConstantNode.forInt(arrayIndexScale))); - } + Registration r = new Registration(plugins, "com.sun.crypto.provider.CipherBlockChaining", replacements); - private ValueNode asWord(ValueNode index) { - assert index.getStackKind().isPrimitive(); - if (index.getStackKind() != wordTypes.getWordKind()) { - return SignExtendNode.create(index, wordTypes.getWordKind().getBitCount(), NodeView.DEFAULT); + Pair cbcEncryptName = selectIntrinsicName(config, "com/sun/crypto/provider/CipherBlockChaining", "implEncrypt", "encrypt"); + try { + r.registerOptional6(cbcEncryptName.getLeft(), Receiver.class, byte[].class, int.class, int.class, byte[].class, int.class, new CipherBlockChainingCryptPlugin(true)); + } catch (NoSuchMethodError e3) { + throw new GraalError(e3, "Found method named '%s' instead of '%s' in class '%s'. This is most likely because the JVMCI JDK in %s was built on an incompatible base JDK.", + cbcEncryptName.getRight(), cbcEncryptName.getLeft(), r.getDeclaringType().getTypeName(), Services.getSavedProperties().get("java.home")); } - return index; - } - private LogicNode createCompare(CanonicalCondition cond, ValueNode a, ValueNode b) { - assert !a.getStackKind().isNumericFloat(); - switch (cond) { - case EQ: - if (a.getStackKind() == JavaKind.Object) { - return ObjectEqualsNode.create(getConstantReflection(), getMetaAccess(), b.getOptions(), a, b, NodeView.DEFAULT); - } else { - return IntegerEqualsNode.create(getConstantReflection(), getMetaAccess(), b.getOptions(), null, a, b, NodeView.DEFAULT); - } - case LT: - assert a.getStackKind() != JavaKind.Object; - return IntegerLessThanNode.create(getConstantReflection(), getMetaAccess(), b.getOptions(), null, a, b, NodeView.DEFAULT); - default: - throw GraalError.shouldNotReachHere("Unexpected condition: " + cond); + Pair cbcDecryptName = selectIntrinsicName(config, "com/sun/crypto/provider/CipherBlockChaining", "implDecrypt", "decrypt"); + try { + r.registerOptional6(cbcDecryptName.getLeft(), Receiver.class, byte[].class, int.class, int.class, byte[].class, int.class, new CipherBlockChainingCryptPlugin(false)); + } catch (NoSuchMethodError e2) { + throw new GraalError(e2, "Found method named '%s' instead of '%s' in class '%s'. This is most likely because the JVMCI JDK in %s was built on an incompatible base JDK.", + cbcDecryptName.getRight(), cbcDecryptName.getLeft(), r.getDeclaringType().getTypeName(), Services.getSavedProperties().get("java.home")); } - } - - private ConstantReflectionProvider getConstantReflection() { - return context.getConstantReflection(); - } - - private MetaAccessProvider getMetaAccess() { - return context.getMetaAccess(); - } - void guard(ValueNode x, Condition condition, ValueNode y, DeoptimizationAction action, DeoptimizationReason deoptReason) { - Condition.CanonicalizedCondition canonicalizedCondition = condition.canonicalize(); + r = new Registration(plugins, "com.sun.crypto.provider.AESCrypt", replacements); - // Check whether the condition needs to mirror the operands. - ValueNode a = x; - ValueNode b = y; - if (canonicalizedCondition.mustMirror()) { - a = y; - b = x; + Pair aesEncryptName = selectIntrinsicName(config, "com/sun/crypto/provider/AESCrypt", "implEncryptBlock", "encryptBlock"); + try { + r.registerOptional5(aesEncryptName.getLeft(), Receiver.class, byte[].class, int.class, byte[].class, int.class, new AESCryptPlugin(true)); + } catch (NoSuchMethodError e1) { + throw new GraalError(e1, "Found method named '%s' instead of '%s' in class '%s'. This is most likely because the JVMCI JDK in %s was built on an incompatible base JDK.", + aesEncryptName.getRight(), aesEncryptName.getLeft(), r.getDeclaringType().getTypeName(), Services.getSavedProperties().get("java.home")); } - LogicNode compare = createCompare(canonicalizedCondition.getCanonicalCondition(), a, b); - context.add(new FixedGuardNode(compare, deoptReason, action, !canonicalizedCondition.mustNegate())); - } - - public ValueNode leftShift(ValueNode node, int i) { - return context.add(new LeftShiftNode(node, ConstantNode.forInt(i))); - } - public ValueNode rightShift(ValueNode node, int i) { - return context.add(new RightShiftNode(node, ConstantNode.forInt(i))); + Pair aesDecryptName = selectIntrinsicName(config, "com/sun/crypto/provider/AESCrypt", "implDecryptBlock", "decryptBlock"); + try { + r.registerOptional5(aesDecryptName.getLeft(), Receiver.class, byte[].class, int.class, byte[].class, int.class, new AESCryptPlugin(false)); + } catch (NoSuchMethodError e) { + throw new GraalError(e, "Found method named '%s' instead of '%s' in class '%s'. This is most likely because the JVMCI JDK in %s was built on an incompatible base JDK.", + aesDecryptName.getRight(), aesDecryptName.getLeft(), r.getDeclaringType().getTypeName(), Services.getSavedProperties().get("java.home")); + } } - } private static void registerBigIntegerPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) { @@ -802,12 +913,13 @@ private static void registerBigIntegerPlugins(InvocationPlugins plugins, GraalHo r.register5("implMulAdd", int[].class, int[].class, int.class, int.class, int.class, new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode out, ValueNode in, ValueNode offset, ValueNode len, ValueNode k) { - ValueNode outNonNull = b.nullCheckedValue(out); - ValueNode outNonNullLength = b.add(new ArrayLengthNode(outNonNull)); - ValueNode newOffset = new SubNode(outNonNullLength, offset); - ForeignCallNode call = new ForeignCallNode(HotSpotBackend.MUL_ADD, byteArrayStart(b, outNonNull), byteArrayStart(b, in), newOffset, len, k); - b.addPush(JavaKind.Int, call); - b.setStateAfter(call); + try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) { + ValueNode outNonNull = b.nullCheckedValue(out); + ValueNode outNonNullLength = b.add(new ArrayLengthNode(outNonNull)); + ValueNode newOffset = new SubNode(outNonNullLength, offset); + ForeignCallNode call = new ForeignCallNode(HotSpotBackend.MUL_ADD, helper.arrayStart(outNonNull, JavaKind.Int), helper.arrayStart(in, JavaKind.Int), newOffset, len, k); + b.addPush(JavaKind.Int, call); + } return true; } }); @@ -818,14 +930,17 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec * int[] product) */ r.register6("implMontgomeryMultiply", int[].class, int[].class, int[].class, int.class, long.class, int[].class, new InvocationPlugin() { + @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode a, ValueNode bObject, ValueNode n, ValueNode len, ValueNode inv, ValueNode product) { - ForeignCallNode call = new ForeignCallNode(HotSpotBackend.MONTGOMERY_MULTIPLY, byteArrayStart(b, a), byteArrayStart(b, bObject), byteArrayStart(b, n), len, inv, - byteArrayStart(b, product)); - b.add(call); - b.addPush(JavaKind.Object, product); - b.setStateAfter(call); + try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) { + // The stub doesn't return the right value for the intrinsic so push it here + // and the proper after FrameState will be put on ForeignCallNode by add. + b.addPush(JavaKind.Object, product); + b.add(new ForeignCallNode(HotSpotBackend.MONTGOMERY_MULTIPLY, helper.arrayStart(a, JavaKind.Int), helper.arrayStart(bObject, JavaKind.Int), + helper.arrayStart(n, JavaKind.Int), len, inv, helper.arrayStart(product, JavaKind.Int))); + } return true; } }); @@ -837,10 +952,13 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec r.register5("implMontgomerySquare", int[].class, int[].class, int.class, long.class, int[].class, new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode a, ValueNode n, ValueNode len, ValueNode inv, ValueNode product) { - ForeignCallNode call = new ForeignCallNode(HotSpotBackend.MONTGOMERY_SQUARE, byteArrayStart(b, a), byteArrayStart(b, n), len, inv, byteArrayStart(b, product)); - b.add(call); - b.addPush(JavaKind.Object, product); - b.setStateAfter(call); + try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) { + // The stub doesn't return the right value for the intrinsic so push it here + // and the proper after FrameState will be put on ForeignCallNode by add. + b.addPush(JavaKind.Object, product); + b.add(new ForeignCallNode(HotSpotBackend.MONTGOMERY_SQUARE, helper.arrayStart(a, JavaKind.Int), helper.arrayStart(n, JavaKind.Int), len, inv, + helper.arrayStart(product, JavaKind.Int))); + } return true; } }); @@ -852,10 +970,12 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec r.register4("implSquareToLen", int[].class, int.class, int[].class, int.class, new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode len, ValueNode z, ValueNode zlen) { - ForeignCallNode call = new ForeignCallNode(HotSpotBackend.SQUARE_TO_LEN, byteArrayStart(b, x), len, byteArrayStart(b, z), zlen); - b.add(call); - b.addPush(JavaKind.Object, z); - b.setStateAfter(call); + try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) { + // The stub doesn't return the right value for the intrinsic so push it here + // and the proper after FrameState will be put on ForeignCallNode by add. + b.addPush(JavaKind.Object, z); + b.add(new ForeignCallNode(HotSpotBackend.SQUARE_TO_LEN, helper.arrayStart(x, JavaKind.Int), len, helper.arrayStart(z, JavaKind.Int), zlen)); + } return true; } }); @@ -882,6 +1002,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec b.add(new ForeignCallNode(descriptor, bufAddr, stateAddr)); return true; } + } private static void registerSHAPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) { @@ -899,19 +1020,34 @@ private static void registerSHAPlugins(InvocationPlugins plugins, GraalHotSpotVM assert config.sha1ImplCompress != 0L; Registration r = new Registration(plugins, "sun.security.provider.SHA", replacements); InvocationPlugin plugin = new SHAInvocationPlugin(HotSpotBackend.SHA_IMPL_COMPRESS); - registerAndCheckMismatch(r, implCompressName, Receiver.class, byte[].class, int.class, plugin); + try { + r.register3(implCompressName.getLeft(), Receiver.class, byte[].class, int.class, plugin); + } catch (NoSuchMethodError e) { + throw new GraalError(e, "Found method named '%s' instead of '%s' in class '%s'. This is most likely because the JVMCI JDK in %s was built on an incompatible base JDK.", + implCompressName.getRight(), implCompressName.getLeft(), r.getDeclaringType().getTypeName(), Services.getSavedProperties().get("java.home")); + } } if (useSha256) { assert config.sha256ImplCompress != 0L; Registration r = new Registration(plugins, "sun.security.provider.SHA2", replacements); InvocationPlugin plugin = new SHAInvocationPlugin(HotSpotBackend.SHA2_IMPL_COMPRESS); - registerAndCheckMismatch(r, implCompressName, Receiver.class, byte[].class, int.class, plugin); + try { + r.register3(implCompressName.getLeft(), Receiver.class, byte[].class, int.class, plugin); + } catch (NoSuchMethodError e) { + throw new GraalError(e, "Found method named '%s' instead of '%s' in class '%s'. This is most likely because the JVMCI JDK in %s was built on an incompatible base JDK.", + implCompressName.getRight(), implCompressName.getLeft(), r.getDeclaringType().getTypeName(), Services.getSavedProperties().get("java.home")); + } } if (useSha512) { assert config.sha512ImplCompress != 0L; Registration r = new Registration(plugins, "sun.security.provider.SHA5", replacements); InvocationPlugin plugin = new SHAInvocationPlugin(HotSpotBackend.SHA5_IMPL_COMPRESS); - registerAndCheckMismatch(r, implCompressName, Receiver.class, byte[].class, int.class, plugin); + try { + r.register3(implCompressName.getLeft(), Receiver.class, byte[].class, int.class, plugin); + } catch (NoSuchMethodError e) { + throw new GraalError(e, "Found method named '%s' instead of '%s' in class '%s'. This is most likely because the JVMCI JDK in %s was built on an incompatible base JDK.", + implCompressName.getRight(), implCompressName.getLeft(), r.getDeclaringType().getTypeName(), Services.getSavedProperties().get("java.home")); + } } } @@ -948,12 +1084,73 @@ public boolean apply(GraphBuilderContext b, } } + static class CounterModeCryptPlugin implements InvocationPlugin { + public static ResolvedJavaType getType(ResolvedJavaType context, String typeName) { + try { + UnresolvedJavaType unresolved = UnresolvedJavaType.create(typeName); + return unresolved.resolve(context); + } catch (LinkageError e) { + throw new GraalError(e); + } + } + + static ResolvedJavaType aesCryptType(ResolvedJavaType context) { + return getType(context, "Lcom/sun/crypto/provider/AESCrypt;"); + } + + static ResolvedJavaType feedbackCipherType(ResolvedJavaType context) { + return getType(context, "Lcom/sun/crypto/provider/FeedbackCipher;"); + } + + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode in, ValueNode inOffset, ValueNode len, ValueNode out, ValueNode outOffset) { + try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) { + ValueNode nonNullReceiver = receiver.get(); + + // Read FeedbackCipher.embeddedCipher + ResolvedJavaField embeddedCipherField = helper.getField(feedbackCipherType(targetMethod.getDeclaringClass()), "embeddedCipher"); + ValueNode embeddedCipher = helper.loadField(nonNullReceiver, embeddedCipherField); + + // Use the fallback path if the embeddedCipher is not an instance of AESCrypt + LogicNode typeCheck = InstanceOfNode.create(TypeReference.create(b.getAssumptions(), aesCryptType(targetMethod.getDeclaringClass())), embeddedCipher); + helper.doFallbackIfNot(typeCheck, GraalDirectives.UNLIKELY_PROBABILITY); + + // Compute pointers to array bodies + ValueNode nonNullIn = b.nullCheckedValue(in); + ValueNode nonNullOut = b.nullCheckedValue(out); + ValueNode inAddr = helper.arrayElementPointer(nonNullIn, JavaKind.Byte, inOffset); + ValueNode outAddr = helper.arrayElementPointer(nonNullOut, JavaKind.Byte, outOffset); + + // Read AESCrypt.K + ResolvedJavaField kField = helper.getField(aesCryptType(targetMethod.getDeclaringClass()), "K"); + ValueNode k = b.nullCheckedValue(helper.loadField(embeddedCipher, kField)); + + // Read CounterModeCrypt.counter + ResolvedJavaField counterField = helper.getField(targetMethod.getDeclaringClass(), "counter"); + ValueNode counter = helper.loadField(nonNullReceiver, counterField); + ValueNode counterAddr = helper.arrayStart(counter, JavaKind.Byte); + + // Read CounterModeCrypt.encryptedCounter + ResolvedJavaField encryptedCounterField = helper.getField(targetMethod.getDeclaringClass(), "encryptedCounter"); + ValueNode encryptedCounter = helper.loadField(nonNullReceiver, encryptedCounterField); + ValueNode encryptedCounterAddr = helper.arrayStart(encryptedCounter, JavaKind.Byte); + ValueNode kAddr = helper.arrayStart(k, JavaKind.Int); + + // Compute address of CounterModeCrypt.used field + ValueNode usedPtr = b.add(new ComputeObjectAddressNode(nonNullReceiver, helper.asWord(helper.getFieldOffset(targetMethod.getDeclaringClass(), "used")))); + ForeignCallNode call = b.add(new ForeignCallNode(COUNTERMODE_IMPL_CRYPT, inAddr, outAddr, kAddr, counterAddr, len, encryptedCounterAddr, usedPtr)); + helper.emitFinalReturn(JavaKind.Int, call); + } + return true; + } + } + private static void registerCounterModePlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) { - if (isIntrinsicName(config, "com/sun/crypto/provider/CounterMode", "implCrypt")) { - assert !config.useAESCTRIntrinsics || config.counterModeAESCrypt != 0L; + if (isIntrinsicName(config, "com/sun/crypto/provider/CounterMode", "implCrypt") && config.useAESCTRIntrinsics) { + assert config.counterModeAESCrypt != 0L; Registration r = new Registration(plugins, "com.sun.crypto.provider.CounterMode", replacements); - r.registerConditionalMethodSubstitution(config.useAESCTRIntrinsics, CounterModeSubstitutions.class, "implCrypt", Receiver.class, byte[].class, int.class, int.class, byte[].class, - int.class); + r.register6("implCrypt", Receiver.class, byte[].class, int.class, int.class, byte[].class, + int.class, new CounterModeCryptPlugin()); } } @@ -995,7 +1192,7 @@ private static void registerCRC32Plugins(InvocationPlugins plugins, GraalHotSpot r.register2("update", int.class, int.class, new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode crc, ValueNode arg) { - final ValueNode crcTableRawAddress = b.add(new GraalHotSpotVMConfigNode(config, HotSpotMarkId.CRC_TABLE_ADDRESS, JavaKind.Long)); + final ValueNode crcTableRawAddress = ConstantNode.forLong(config.crcTableAddress); ValueNode c = new XorNode(crc, ConstantNode.forInt(-1)); ValueNode index = new AndNode(new XorNode(arg, c), ConstantNode.forInt(0xff)); ValueNode offset = new LeftShiftNode(index, ConstantNode.forInt(2)); diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java index 2f5397769357..a424e30de1f3 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java @@ -25,23 +25,17 @@ package org.graalvm.compiler.hotspot.meta; import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_DREM; import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_FREM; -import static org.graalvm.compiler.hotspot.HotSpotBackend.BACKEDGE_EVENT; +import static org.graalvm.compiler.hotspot.HotSpotBackend.AESCRYPT_DECRYPTBLOCK; +import static org.graalvm.compiler.hotspot.HotSpotBackend.AESCRYPT_ENCRYPTBLOCK; import static org.graalvm.compiler.hotspot.HotSpotBackend.BASE64_ENCODE_BLOCK; +import static org.graalvm.compiler.hotspot.HotSpotBackend.CIPHER_BLOCK_CHAINING_DECRYPT_AESCRYPT; +import static org.graalvm.compiler.hotspot.HotSpotBackend.CIPHER_BLOCK_CHAINING_ENCRYPT_AESCRYPT; import static org.graalvm.compiler.hotspot.HotSpotBackend.COUNTERMODE_IMPL_CRYPT; -import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT; -import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_BLOCK; -import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_BLOCK_WITH_ORIGINAL_KEY; -import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_WITH_ORIGINAL_KEY; -import static org.graalvm.compiler.hotspot.HotSpotBackend.ENCRYPT; -import static org.graalvm.compiler.hotspot.HotSpotBackend.ENCRYPT_BLOCK; import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER; import static org.graalvm.compiler.hotspot.HotSpotBackend.GHASH_PROCESS_BLOCKS; import static org.graalvm.compiler.hotspot.HotSpotBackend.IC_MISS_HANDLER; -import static org.graalvm.compiler.hotspot.HotSpotBackend.INITIALIZE_KLASS_BY_SYMBOL; -import static org.graalvm.compiler.hotspot.HotSpotBackend.INVOCATION_EVENT; import static org.graalvm.compiler.hotspot.HotSpotBackend.MONTGOMERY_MULTIPLY; import static org.graalvm.compiler.hotspot.HotSpotBackend.MONTGOMERY_SQUARE; import static org.graalvm.compiler.hotspot.HotSpotBackend.MULTIPLY_TO_LEN; @@ -52,10 +46,6 @@ import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_INSTANCE_OR_NULL; import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_MULTI_ARRAY; import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_MULTI_ARRAY_OR_NULL; -import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE; -import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL; -import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS; -import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL; import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA2_IMPL_COMPRESS; import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA2_IMPL_COMPRESS_MB; import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA5_IMPL_COMPRESS; @@ -66,7 +56,6 @@ import static org.graalvm.compiler.hotspot.HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER; import static org.graalvm.compiler.hotspot.HotSpotBackend.VECTORIZED_MISMATCH; import static org.graalvm.compiler.hotspot.HotSpotBackend.VM_ERROR; -import static org.graalvm.compiler.hotspot.HotSpotBackend.WRONG_METHOD_HANDLER; import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.COMPUTES_REGISTERS_KILLED; import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_ALL_CALLER_SAVE_REGISTERS; import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPT_BLOB_UNCOMMON_TRAP; @@ -111,9 +100,9 @@ import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.hotspot.ArrayIndexOfStub; -import org.graalvm.compiler.hotspot.CompilerRuntimeHotSpotVMConfig; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.hotspot.replacements.arraycopy.CheckcastArrayCopyCallNode; import org.graalvm.compiler.hotspot.stubs.ArrayStoreExceptionStub; import org.graalvm.compiler.hotspot.stubs.ClassCastExceptionStub; import org.graalvm.compiler.hotspot.stubs.CreateExceptionStub; @@ -122,6 +111,7 @@ import org.graalvm.compiler.hotspot.stubs.IllegalArgumentExceptionArgumentIsNotAnArrayStub; import org.graalvm.compiler.hotspot.stubs.IntegerExactOverflowExceptionStub; import org.graalvm.compiler.hotspot.stubs.LongExactOverflowExceptionStub; +import org.graalvm.compiler.hotspot.stubs.NegativeArraySizeExceptionStub; import org.graalvm.compiler.hotspot.stubs.NullPointerExceptionStub; import org.graalvm.compiler.hotspot.stubs.OutOfBoundsExceptionStub; import org.graalvm.compiler.hotspot.stubs.Stub; @@ -130,8 +120,8 @@ import org.graalvm.compiler.nodes.NamedLocationIdentity; import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.replacements.SnippetTemplate; import org.graalvm.compiler.replacements.ArrayIndexOf; +import org.graalvm.compiler.replacements.SnippetTemplate; import org.graalvm.compiler.replacements.arraycopy.ArrayCopyForeignCalls; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.compiler.word.Word; @@ -158,6 +148,25 @@ public abstract class HotSpotHostForeignCallsProvider extends HotSpotForeignCall public static final HotSpotForeignCallDescriptor INVOKE_STATIC_METHOD_ONE_ARG = new HotSpotForeignCallDescriptor(SAFEPOINT, REEXECUTABLE, NO_LOCATIONS, "JVMCIRuntime::invoke_static_method_one_arg", long.class, Word.class, Word.class, long.class); + /** + * Signature of an unsafe {@link System#arraycopy} stub. + * + * The signature is equivalent to {@link sun.misc.Unsafe#copyMemory(long, long, long)}. For the + * semantics refer to {@link sun.misc.Unsafe#copyMemory(Object, long, Object, long, long)}. + * + * @see sun.misc.Unsafe#copyMemory + */ + public static final ForeignCallSignature UNSAFE_ARRAYCOPY = new ForeignCallSignature("unsafe_arraycopy", void.class, Word.class, Word.class, Word.class); + + /** + * Signature of a generic {@link System#arraycopy} stub. + * + * Instead of throwing an {@link ArrayStoreException}, the stub is expected to return the number + * of copied elements xor'd with {@code -1}. A return value of {@code 0} indicates that the + * operation was successful. + */ + public static final ForeignCallSignature GENERIC_ARRAYCOPY = new ForeignCallSignature("generic_arraycopy", int.class, Word.class, int.class, Word.class, int.class, int.class); + public static class TestForeignCalls { public static final HotSpotForeignCallDescriptor BOOLEAN_RETURNS_BOOLEAN = new HotSpotForeignCallDescriptor(SAFEPOINT, REEXECUTABLE, NO_LOCATIONS, "boolean returns boolean", Boolean.TYPE, Boolean.TYPE); @@ -217,7 +226,11 @@ protected static void link(Stub stub) { stub.getLinkage().setCompiledStub(stub); } - @Override + /** + * Looks up the call descriptor for a fast checkcast {@link System#arraycopy} stub. + * + * @see CheckcastArrayCopyCallNode + */ public ForeignCallDescriptor lookupCheckcastArraycopyDescriptor(boolean uninit) { return checkcastArraycopyDescriptors[uninit ? 1 : 0]; } @@ -463,6 +476,8 @@ public void initialize(HotSpotProviders providers, OptionValues options) { registerStubCall(exceptionRuntimeCalls.get(BytecodeExceptionKind.NULL_POINTER), SAFEPOINT, NOT_REEXECUTABLE, DESTROYS_ALL_CALLER_SAVE_REGISTERS, any()))); link(new OutOfBoundsExceptionStub(options, providers, registerStubCall(exceptionRuntimeCalls.get(BytecodeExceptionKind.OUT_OF_BOUNDS), SAFEPOINT, NOT_REEXECUTABLE, DESTROYS_ALL_CALLER_SAVE_REGISTERS, any()))); + link(new NegativeArraySizeExceptionStub(options, providers, + registerStubCall(exceptionRuntimeCalls.get(BytecodeExceptionKind.NEGATIVE_ARRAY_SIZE), SAFEPOINT, NOT_REEXECUTABLE, DESTROYS_ALL_CALLER_SAVE_REGISTERS, any()))); link(new DivisionByZeroExceptionStub(options, providers, registerStubCall(exceptionRuntimeCalls.get(BytecodeExceptionKind.DIVISION_BY_ZERO), SAFEPOINT, NOT_REEXECUTABLE, DESTROYS_ALL_CALLER_SAVE_REGISTERS, any()))); link(new IntegerExactOverflowExceptionStub(options, providers, @@ -492,18 +507,6 @@ public void initialize(HotSpotProviders providers, OptionValues options) { linkForeignCall(options, providers, G1WBPOSTCALL, c.writeBarrierPostAddress, PREPEND_THREAD); linkForeignCall(options, providers, VALIDATE_OBJECT, c.validateObject, PREPEND_THREAD); - if (GeneratePIC.getValue(options)) { - registerForeignCall(WRONG_METHOD_HANDLER, c.handleWrongMethodStub, NativeCall); - CompilerRuntimeHotSpotVMConfig cr = new CompilerRuntimeHotSpotVMConfig(HotSpotJVMCIRuntime.runtime().getConfigStore()); - linkForeignCall(options, providers, RESOLVE_STRING_BY_SYMBOL, cr.resolveStringBySymbol, PREPEND_THREAD); - linkForeignCall(options, providers, RESOLVE_DYNAMIC_INVOKE, cr.resolveDynamicInvoke, PREPEND_THREAD); - linkForeignCall(options, providers, RESOLVE_KLASS_BY_SYMBOL, cr.resolveKlassBySymbol, PREPEND_THREAD); - linkForeignCall(options, providers, RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS, cr.resolveMethodBySymbolAndLoadCounters, PREPEND_THREAD); - linkForeignCall(options, providers, INITIALIZE_KLASS_BY_SYMBOL, cr.initializeKlassBySymbol, PREPEND_THREAD); - linkForeignCall(options, providers, INVOCATION_EVENT, cr.invocationEvent, PREPEND_THREAD); - linkForeignCall(options, providers, BACKEDGE_EVENT, cr.backedgeEvent, PREPEND_THREAD); - } - linkForeignCall(options, providers, TEST_DEOPTIMIZE_CALL_INT, c.testDeoptimizeCallInt, PREPEND_THREAD); registerArrayCopy(JavaKind.Byte, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy); @@ -566,9 +569,8 @@ public void initialize(HotSpotProviders providers, OptionValues options) { */ try { // These stubs do callee saving - registerForeignCall(ENCRYPT_BLOCK, c.aescryptEncryptBlockStub, NativeCall); - registerForeignCall(DECRYPT_BLOCK, c.aescryptDecryptBlockStub, NativeCall); - registerForeignCall(DECRYPT_BLOCK_WITH_ORIGINAL_KEY, c.aescryptDecryptBlockStub, NativeCall); + registerForeignCall(AESCRYPT_ENCRYPTBLOCK, c.aescryptEncryptBlockStub, NativeCall); + registerForeignCall(AESCRYPT_DECRYPTBLOCK, c.aescryptDecryptBlockStub, NativeCall); } catch (GraalError e) { if (!(e.getCause() instanceof ClassNotFoundException)) { throw e; @@ -576,9 +578,8 @@ public void initialize(HotSpotProviders providers, OptionValues options) { } try { // These stubs do callee saving - registerForeignCall(ENCRYPT, c.cipherBlockChainingEncryptAESCryptStub, NativeCall); - registerForeignCall(DECRYPT, c.cipherBlockChainingDecryptAESCryptStub, NativeCall); - registerForeignCall(DECRYPT_WITH_ORIGINAL_KEY, c.cipherBlockChainingDecryptAESCryptStub, NativeCall); + registerForeignCall(CIPHER_BLOCK_CHAINING_ENCRYPT_AESCRYPT, c.cipherBlockChainingEncryptAESCryptStub, NativeCall); + registerForeignCall(CIPHER_BLOCK_CHAINING_DECRYPT_AESCRYPT, c.cipherBlockChainingDecryptAESCryptStub, NativeCall); } catch (GraalError e) { if (!(e.getCause() instanceof ClassNotFoundException)) { throw e; diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java index 54175cfb416c..982e271339c8 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java @@ -31,23 +31,17 @@ import java.util.List; import java.util.function.Predicate; -import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.iterators.NodeIterable; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; -import org.graalvm.compiler.hotspot.phases.AheadOfTimeVerificationPhase; -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; -import org.graalvm.compiler.nodes.type.StampTool; import org.graalvm.compiler.phases.tiers.CompilerConfiguration; import org.graalvm.compiler.replacements.nodes.MacroInvokable; -import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaType; /** @@ -72,7 +66,12 @@ final class HotSpotInvocationPlugins extends InvocationPlugins { protected void register(InvocationPlugin plugin, boolean isOptional, boolean allowOverwrite, Type declaringClass, String name, Type... argumentTypes) { if (!config.usePopCountInstruction) { if (name.equals("bitCount")) { - assert declaringClass.equals(Integer.class) || declaringClass.equals(Long.class); + GraalError.guarantee(declaringClass.equals(Integer.class) || declaringClass.equals(Long.class), declaringClass.getTypeName()); + return; + } + } + if (!config.useUnalignedAccesses) { + if (name.endsWith("Unaligned") && declaringClass.getTypeName().equals("jdk.internal.misc.Unsafe")) { return; } } @@ -86,34 +85,12 @@ public void checkNewNodes(GraphBuilderContext b, InvocationPlugin plugin, NodeIt // MacroNode based plugins can only be used for inlining since they // require a valid bci should they need to replace themselves with // an InvokeNode during lowering. - assert plugin.inlineOnly() : String.format("plugin that creates a %s (%s) must return true for inlineOnly(): %s", MacroInvokable.class.getSimpleName(), node, plugin); - } - } - if (GraalOptions.ImmutableCode.getValue(b.getOptions())) { - for (Node node : newNodes) { - if (node.hasUsages() && node instanceof ConstantNode) { - ConstantNode c = (ConstantNode) node; - if (c.getStackKind() == JavaKind.Object && AheadOfTimeVerificationPhase.isIllegalObjectConstant(c)) { - if (isClass(c)) { - // This will be handled later by LoadJavaMirrorWithKlassPhase - } else { - // Tolerate uses in unused FrameStates - if (node.usages().filter((n) -> !(n instanceof FrameState) || n.hasUsages()).isNotEmpty()) { - throw new AssertionError("illegal constant node in AOT: " + node); - } - } - } - } + GraalError.guarantee(plugin.inlineOnly(), "plugin that creates a %s (%s) must return true for inlineOnly(): %s", MacroInvokable.class.getSimpleName(), node, plugin); } } super.checkNewNodes(b, plugin, newNodes); } - private static boolean isClass(ConstantNode node) { - ResolvedJavaType type = StampTool.typeOrNull(node); - return type != null && "Ljava/lang/Class;".equals(type.getName()); - } - @Override public void registerIntrinsificationPredicate(Predicate predicate) { intrinsificationPredicates.add(predicate); diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvokeDynamicPlugin.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvokeDynamicPlugin.java deleted file mode 100644 index 12d85d3bc6d5..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvokeDynamicPlugin.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.meta; - -import org.graalvm.compiler.bytecode.Bytecodes; -import org.graalvm.compiler.core.common.type.Stamp; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode; -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.FrameState; -import org.graalvm.compiler.nodes.NodeView; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.graphbuilderconf.InvokeDynamicPlugin; -import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; - -import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; -import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; -import jdk.vm.ci.meta.ConstantPool; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.ResolvedJavaMethod; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -public class HotSpotInvokeDynamicPlugin implements InvokeDynamicPlugin { - - private static final Class hscp; - private static final MethodHandle isResolvedDynamicInvokeMH; - - static { - MethodHandle m = null; - Class c = null; - try { - c = Class.forName("jdk.vm.ci.hotspot.HotSpotConstantPool").asSubclass(ConstantPool.class); - m = MethodHandles.lookup().findVirtual(c, "isResolvedDynamicInvoke", MethodType.methodType(boolean.class, int.class, int.class)); - } catch (Exception e) { - } - isResolvedDynamicInvokeMH = m; - hscp = c; - } - - private static boolean isResolvedDynamicInvoke(ConstantPool constantPool, int index, int opcode) { - if (isResolvedDynamicInvokeMH != null) { - if (!hscp.isInstance(constantPool)) { - return false; - } - try { - return (boolean) isResolvedDynamicInvokeMH.invoke(constantPool, index, opcode); - } catch (Throwable t) { - throw GraalError.shouldNotReachHere(t); - } - } - throw GraalError.shouldNotReachHere("isResolvedDynamicInvokeMH not set"); - } - - private final DynamicTypeStore dynoStore; - private final boolean treatAppendixAsConstant; - - public HotSpotInvokeDynamicPlugin(DynamicTypeStore dynoStore, boolean treatAppendixAsConstant) { - this.dynoStore = dynoStore; - this.treatAppendixAsConstant = treatAppendixAsConstant; - } - - public HotSpotInvokeDynamicPlugin(DynamicTypeStore dynoStore) { - this(dynoStore, true); - } - - public HotSpotInvokeDynamicPlugin() { - this(null); - } - - // invokehandle support - @Override - public boolean isResolvedDynamicInvoke(GraphBuilderContext builder, int index, int opcode) { - ConstantPool constantPool = builder.getCode().getConstantPool(); - if (isResolvedDynamicInvokeMH == null) { - // If older JVMCI, but HotSpotInvokeDynamicPlugin is being - // used for testing, return true so that we continue along the - // plugin path. - return true; - } - return isResolvedDynamicInvoke(constantPool, index, opcode); - } - - @Override - public boolean supportsDynamicInvoke(GraphBuilderContext builder, int index, int opcode) { - return opcode == Bytecodes.INVOKEDYNAMIC || isResolvedDynamicInvokeMH != null; - } - - public DynamicTypeStore getDynamicTypeStore() { - return dynoStore; - } - - @Override - public void recordDynamicMethod(GraphBuilderContext builder, int index, int opcode, ResolvedJavaMethod target) { - assert supportsDynamicInvoke(builder, index, opcode); - HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) builder.getMethod(); - HotSpotResolvedObjectType methodHolder = method.getDeclaringClass(); - - HotSpotResolvedJavaMethod adapter = (HotSpotResolvedJavaMethod) target; - if (dynoStore != null) { - dynoStore.recordAdapter(opcode, methodHolder, index, adapter); - } - } - - @Override - public ValueNode genAppendixNode(GraphBuilderContext builder, int index, int opcode, JavaConstant appendixConstant, FrameState frameState) { - JavaConstant appendix = appendixConstant; - assert supportsDynamicInvoke(builder, index, opcode); - HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) builder.getMethod(); - HotSpotResolvedObjectType methodHolder = method.getDeclaringClass(); - - if (dynoStore != null) { - appendix = dynoStore.recordAppendix(opcode, methodHolder, index, appendix); - } - - ConstantNode appendixNode = ConstantNode.forConstant(appendix, builder.getMetaAccess(), builder.getGraph()); - - Stamp appendixStamp = appendixNode.stamp(NodeView.DEFAULT); - Stamp resolveStamp = treatAppendixAsConstant ? appendixStamp : appendixStamp.unrestricted(); - ResolveDynamicConstantNode resolveNode = new ResolveDynamicConstantNode(resolveStamp, appendixNode); - ResolveDynamicConstantNode added = builder.append(resolveNode); - assert added == resolveNode; - added.setStateBefore(frameState); - return resolveNode; - } - - public interface DynamicTypeStore { - - void recordAdapter(int opcode, HotSpotResolvedObjectType holder, int cpi, HotSpotResolvedJavaMethod adapter); - - JavaConstant recordAppendix(int opcode, HotSpotResolvedObjectType holder, int cpi, JavaConstant appendix); - - } - -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java index 51338b6e8f44..11a1c06138ae 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java @@ -24,8 +24,6 @@ */ package org.graalvm.compiler.hotspot.meta; -import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; - import org.graalvm.compiler.core.common.type.StampPair; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.ValueNode; @@ -93,12 +91,10 @@ public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Va @Override public boolean handleLoadField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field) { - if (!ImmutableCode.getValue(b.getOptions()) || b.parsingIntrinsic()) { - if (object.isConstant()) { - JavaConstant asJavaConstant = object.asJavaConstant(); - if (tryReadField(b, field, asJavaConstant)) { - return true; - } + if (object.isConstant()) { + JavaConstant asJavaConstant = object.asJavaConstant(); + if (tryReadField(b, field, asJavaConstant)) { + return true; } } if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadField(b, object, field)) { @@ -109,10 +105,8 @@ public boolean handleLoadField(GraphBuilderContext b, ValueNode object, Resolved @Override public boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField field) { - if (!ImmutableCode.getValue(b.getOptions()) || b.parsingIntrinsic()) { - if (tryReadField(b, field, null)) { - return true; - } + if (tryReadField(b, field, null)) { + return true; } if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadStaticField(b, field)) { return true; diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotProfilingPlugin.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotProfilingPlugin.java deleted file mode 100644 index 221cef20885d..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotProfilingPlugin.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.meta; - -import org.graalvm.compiler.hotspot.nodes.profiling.ProfileBranchNode; -import org.graalvm.compiler.hotspot.nodes.profiling.ProfileInvokeNode; -import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode; -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.FrameState; -import org.graalvm.compiler.nodes.LogicNode; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.calc.ConditionalNode; -import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; -import org.graalvm.compiler.nodes.graphbuilderconf.ProfilingPlugin; -import org.graalvm.compiler.options.Option; -import org.graalvm.compiler.options.OptionKey; -import org.graalvm.compiler.options.OptionType; -import org.graalvm.compiler.options.OptionValues; - -import jdk.vm.ci.meta.ResolvedJavaMethod; - -public abstract class HotSpotProfilingPlugin implements ProfilingPlugin { - public static class Options { - @Option(help = "Emit profiling of invokes", type = OptionType.Expert)// - public static final OptionKey ProfileInvokes = new OptionKey<>(true); - @Option(help = "Emit profiling of backedges", type = OptionType.Expert)// - public static final OptionKey ProfileBackedges = new OptionKey<>(true); - } - - public abstract int invokeNotifyFreqLog(OptionValues options); - - public abstract int invokeInlineeNotifyFreqLog(OptionValues options); - - public abstract int invokeProfilePobabilityLog(OptionValues options); - - public abstract int backedgeNotifyFreqLog(OptionValues options); - - public abstract int backedgeProfilePobabilityLog(OptionValues options); - - @Override - public boolean shouldProfile(GraphBuilderContext builder, ResolvedJavaMethod method) { - return !builder.parsingIntrinsic(); - } - - @Override - public void profileInvoke(GraphBuilderContext builder, ResolvedJavaMethod method, FrameState frameState) { - assert shouldProfile(builder, method); - OptionValues options = builder.getOptions(); - if (Options.ProfileInvokes.getValue(options) && !method.isClassInitializer()) { - ProfileNode p = builder.append(new ProfileInvokeNode(method, invokeNotifyFreqLog(options), invokeProfilePobabilityLog(options))); - p.setStateBefore(frameState); - } - } - - @Override - public void profileGoto(GraphBuilderContext builder, ResolvedJavaMethod method, int bci, int targetBci, FrameState frameState) { - assert shouldProfile(builder, method); - OptionValues options = builder.getOptions(); - if (Options.ProfileBackedges.getValue(options) && targetBci <= bci) { - ProfileNode p = builder.append(new ProfileBranchNode(method, backedgeNotifyFreqLog(options), backedgeProfilePobabilityLog(options), bci, targetBci)); - p.setStateBefore(frameState); - } - } - - @Override - public void profileIf(GraphBuilderContext builder, ResolvedJavaMethod method, int bci, LogicNode condition, int trueBranchBci, int falseBranchBci, FrameState frameState) { - assert shouldProfile(builder, method); - OptionValues options = builder.getOptions(); - if (Options.ProfileBackedges.getValue(options) && (falseBranchBci <= bci || trueBranchBci <= bci)) { - boolean negate = false; - int targetBci = trueBranchBci; - if (falseBranchBci <= bci) { - assert trueBranchBci > bci; - negate = true; - targetBci = falseBranchBci; - } else { - assert trueBranchBci <= bci && falseBranchBci > bci; - } - ValueNode trueValue = builder.append(ConstantNode.forBoolean(!negate)); - ValueNode falseValue = builder.append(ConstantNode.forBoolean(negate)); - ConditionalNode branchCondition = builder.append(new ConditionalNode(condition, trueValue, falseValue)); - ProfileNode p = builder.append(new ProfileBranchNode(method, backedgeNotifyFreqLog(options), backedgeProfilePobabilityLog(options), branchCondition, bci, targetBci)); - p.setStateBefore(frameState); - } - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java index 2e362cc97d8c..b4a2de09526f 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java @@ -24,13 +24,6 @@ */ package org.graalvm.compiler.hotspot.meta; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; -import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; -import static org.graalvm.compiler.core.common.GraalOptions.VerifyPhases; -import static org.graalvm.compiler.core.phases.HighTier.Options.Inline; - -import java.util.ListIterator; - import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.HotSpotBackend; @@ -38,12 +31,6 @@ import org.graalvm.compiler.hotspot.HotSpotInstructionProfiling; import org.graalvm.compiler.hotspot.lir.HotSpotZapRegistersPhase; import org.graalvm.compiler.hotspot.lir.VerifyMaxRegisterSizePhase; -import org.graalvm.compiler.hotspot.phases.AheadOfTimeVerificationPhase; -import org.graalvm.compiler.hotspot.phases.LoadJavaMirrorWithKlassPhase; -import org.graalvm.compiler.hotspot.phases.aot.AOTInliningPolicy; -import org.graalvm.compiler.hotspot.phases.aot.EliminateRedundantInitializationPhase; -import org.graalvm.compiler.hotspot.phases.aot.ReplaceConstantNodesPhase; -import org.graalvm.compiler.hotspot.phases.profiling.FinalizeProfileNodesPhase; import org.graalvm.compiler.java.GraphBuilderPhase; import org.graalvm.compiler.java.SuitesProviderBase; import org.graalvm.compiler.lir.phases.LIRSuites; @@ -56,12 +43,7 @@ import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.BasePhase; import org.graalvm.compiler.phases.PhaseSuite; -import org.graalvm.compiler.phases.common.CanonicalizerPhase; -import org.graalvm.compiler.phases.common.LoweringPhase; -import org.graalvm.compiler.phases.common.inlining.InliningPhase; import org.graalvm.compiler.phases.tiers.HighTierContext; -import org.graalvm.compiler.phases.tiers.LowTierContext; -import org.graalvm.compiler.phases.tiers.MidTierContext; import org.graalvm.compiler.phases.tiers.Suites; import org.graalvm.compiler.phases.tiers.SuitesCreator; @@ -84,42 +66,7 @@ public HotSpotSuitesProvider(SuitesCreator defaultSuitesCreator, GraalHotSpotVMC @Override public Suites createSuites(OptionValues options) { - Suites ret = defaultSuitesCreator.createSuites(options); - - if (ImmutableCode.getValue(options)) { - ListIterator> midTierLowering = ret.getMidTier().findPhase(LoweringPhase.class); - - // lowering introduces class constants, therefore it must be after lowering - midTierLowering.add(new LoadJavaMirrorWithKlassPhase(config)); - - if (VerifyPhases.getValue(options)) { - midTierLowering.add(new AheadOfTimeVerificationPhase()); - } - - if (GeneratePIC.getValue(options)) { - ListIterator> highTierLowering = ret.getHighTier().findPhase(LoweringPhase.class); - highTierLowering.previous(); - highTierLowering.add(new EliminateRedundantInitializationPhase()); - if (HotSpotAOTProfilingPlugin.Options.TieredAOT.getValue(options)) { - highTierLowering.add(new FinalizeProfileNodesPhase(HotSpotAOTProfilingPlugin.Options.TierAInvokeInlineeNotifyFreqLog.getValue(options))); - } - midTierLowering.add(new ReplaceConstantNodesPhase(true)); - - // Replace possible constants after GC barrier expansion. - ListIterator> lowTierLowering = ret.getLowTier().findPhase(LoweringPhase.class); - lowTierLowering.add(new ReplaceConstantNodesPhase(false)); - - // Replace inlining policy - if (Inline.getValue(options)) { - ListIterator> iter = ret.getHighTier().findPhase(InliningPhase.class); - InliningPhase inlining = (InliningPhase) iter.previous(); - CanonicalizerPhase canonicalizer = inlining.getCanonicalizer(); - iter.set(new InliningPhase(new AOTInliningPolicy(null), canonicalizer)); - } - } - } - - return ret; + return defaultSuitesCreator.createSuites(options); } protected PhaseSuite createGraphBuilderSuite() { @@ -144,7 +91,7 @@ protected void run(StructuredGraph graph, HighTierContext context) { StructuredGraph targetGraph = new StructuredGraph.Builder(graph.getOptions(), graph.getDebug(), AllowAssumptions.YES).method(graph.method()).trackNodeSourcePosition( graph.trackNodeSourcePosition()).build(); - SimplifyingGraphDecoder graphDecoder = new SimplifyingGraphDecoder(runtime.getTarget().arch, targetGraph, context, !ImmutableCode.getValue(graph.getOptions())); + SimplifyingGraphDecoder graphDecoder = new SimplifyingGraphDecoder(runtime.getTarget().arch, targetGraph, context, true); graphDecoder.decode(encodedGraph); } diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/GraalHotSpotVMConfigNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/GraalHotSpotVMConfigNode.java deleted file mode 100644 index 2ea6f9b7dd1f..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/GraalHotSpotVMConfigNode.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.nodes; - -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; -import static org.graalvm.compiler.core.common.GraalOptions.AOTVerifyOops; -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; - -import org.graalvm.compiler.core.common.type.Stamp; -import org.graalvm.compiler.core.common.type.StampFactory; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.Node.NodeIntrinsicFactory; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.Canonicalizable; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; -import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; -import org.graalvm.compiler.hotspot.HotSpotMarkId; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.calc.FloatingNode; -import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; -import org.graalvm.compiler.nodes.spi.LIRLowerable; -import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; - -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.Value; - -/** - * Represents {@link GraalHotSpotVMConfig} values that may change after compilation. - */ -@NodeInfo(cycles = CYCLES_1, size = SIZE_1) -@NodeIntrinsicFactory -public class GraalHotSpotVMConfigNode extends FloatingNode implements LIRLowerable, Canonicalizable { - public static final NodeClass TYPE = NodeClass.create(GraalHotSpotVMConfigNode.class); - - private final GraalHotSpotVMConfig config; - protected final HotSpotMarkId markId; - - /** - * Constructor for node intrinsics below. - * - * @param config - * @param markId id of the config value - */ - public GraalHotSpotVMConfigNode(@InjectedNodeParameter Stamp stamp, @InjectedNodeParameter GraalHotSpotVMConfig config, HotSpotMarkId markId) { - super(TYPE, stamp); - this.config = config; - this.markId = markId; - assert markId != null; - } - - /** - * Constructor with explicit type specification. - * - * @param config - * @param markId id of the config value - * @param kind explicit type of the node - */ - public GraalHotSpotVMConfigNode(GraalHotSpotVMConfig config, HotSpotMarkId markId, JavaKind kind) { - super(TYPE, StampFactory.forKind(kind)); - this.config = config; - this.markId = markId; - assert markId != null; - } - - @Override - public void generate(NodeLIRBuilderTool generator) { - Value res = ((HotSpotLIRGenerator) generator.getLIRGeneratorTool()).emitLoadConfigValue(markId, generator.getLIRGeneratorTool().getLIRKind(stamp)); - generator.setResult(this, res); - } - - @NodeIntrinsic - private static native long loadLongConfigValue(@ConstantNodeParameter HotSpotMarkId markId); - - @NodeIntrinsic - private static native int loadIntConfigValue(@ConstantNodeParameter HotSpotMarkId markId); - - @NodeIntrinsic - private static native boolean loadBoolConfigValue(@ConstantNodeParameter HotSpotMarkId markId); - - public static long cardTableAddress() { - return loadLongConfigValue(HotSpotMarkId.CARD_TABLE_ADDRESS); - } - - public static long crcTableAddress() { - return loadLongConfigValue(HotSpotMarkId.CRC_TABLE_ADDRESS); - } - - public static int logOfHeapRegionGrainBytes() { - return loadIntConfigValue(HotSpotMarkId.LOG_OF_HEAP_REGION_GRAIN_BYTES); - } - - public static boolean verifyOops() { - return loadBoolConfigValue(HotSpotMarkId.VERIFY_OOPS); - } - - public static long verifyOopBits() { - return loadLongConfigValue(HotSpotMarkId.VERIFY_OOP_BITS); - } - - public static long verifyOopMask() { - return loadLongConfigValue(HotSpotMarkId.VERIFY_OOP_MASK); - } - - public static long verifyOopCounterAddress() { - return loadLongConfigValue(HotSpotMarkId.VERIFY_OOP_COUNT_ADDRESS); - } - - public static boolean intrinsify(GraphBuilderContext b, @InjectedNodeParameter Stamp returnStamp, @InjectedNodeParameter GraalHotSpotVMConfig config, HotSpotMarkId mark) { - if (b.getReplacements().isEncodingSnippets()) { - // This plugin must be deferred so that these constants aren't embedded in libgraal - return false; - } - b.addPush(returnStamp.getStackKind(), new GraalHotSpotVMConfigNode(returnStamp, config, mark)); - return true; - } - - @Override - public Node canonical(CanonicalizerTool tool) { - boolean generatePIC = GeneratePIC.getValue(tool.getOptions()); - boolean aotVerifyOops = AOTVerifyOops.getValue(tool.getOptions()); - if (!generatePIC || !markId.isAvailable()) { - if (markId == HotSpotMarkId.CARD_TABLE_ADDRESS) { - return ConstantNode.forLong(config.cardtableStartAddress); - } else if (markId == HotSpotMarkId.CRC_TABLE_ADDRESS) { - return ConstantNode.forLong(config.crcTableAddress); - } else if (markId == HotSpotMarkId.LOG_OF_HEAP_REGION_GRAIN_BYTES) { - return ConstantNode.forInt(config.logOfHRGrainBytes); - } else if (markId == HotSpotMarkId.VERIFY_OOPS) { - return ConstantNode.forBoolean(config.verifyOops); - } else if (markId == HotSpotMarkId.VERIFY_OOP_BITS) { - return ConstantNode.forLong(config.verifyOopBits); - } else if (markId == HotSpotMarkId.VERIFY_OOP_MASK) { - return ConstantNode.forLong(config.verifyOopMask); - } else if (markId == HotSpotMarkId.VERIFY_OOP_COUNT_ADDRESS) { - return ConstantNode.forLong(config.verifyOopCounterAddress); - } else { - throw GraalError.shouldNotReachHere(markId.toString()); - } - } else if (generatePIC && !aotVerifyOops) { - if (markId == HotSpotMarkId.VERIFY_OOPS) { - return ConstantNode.forBoolean(false); - } else if (markId == HotSpotMarkId.VERIFY_OOP_BITS) { - return ConstantNode.forLong(0L); - } else if (markId == HotSpotMarkId.VERIFY_OOP_MASK) { - return ConstantNode.forLong(0L); - } else if (markId == HotSpotMarkId.VERIFY_OOP_COUNT_ADDRESS) { - return ConstantNode.forLong(0L); - } - } - return this; - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/EncodedSymbolNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/EncodedSymbolNode.java deleted file mode 100644 index 08d7d4b3d5eb..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/EncodedSymbolNode.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.nodes.aot; - -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; - -import org.graalvm.compiler.core.common.type.Stamp; -import org.graalvm.compiler.core.common.type.StampFactory; -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.Canonicalizable; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; -import org.graalvm.compiler.hotspot.replacements.EncodedSymbolConstant; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.calc.FloatingNode; -import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.compiler.word.Word; - -import jdk.vm.ci.meta.Constant; - -@NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) -public final class EncodedSymbolNode extends FloatingNode implements Canonicalizable { - - public static final NodeClass TYPE = NodeClass.create(EncodedSymbolNode.class); - - @OptionalInput protected ValueNode value; - - public EncodedSymbolNode(@InjectedNodeParameter Stamp stamp, ValueNode value) { - super(TYPE, stamp); - assert value != null; - this.value = value; - } - - @Override - public Node canonical(CanonicalizerTool tool) { - if (value != null) { - Constant constant = GraphUtil.foldIfConstantAndRemove(this, value); - if (constant != null) { - return new ConstantNode(new EncodedSymbolConstant(constant), StampFactory.pointer()); - } - } - return this; - } - - @NodeIntrinsic - public static native Word encode(Object constant); -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassNode.java deleted file mode 100644 index 53fddb8ae0c5..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassNode.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.nodes.aot; - -import static org.graalvm.compiler.nodeinfo.InputType.Memory; -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16; - -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode; -import org.graalvm.compiler.nodes.NodeView; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.memory.SingleMemoryKill; -import org.graalvm.compiler.nodes.spi.Lowerable; -import org.graalvm.word.LocationIdentity; - -@NodeInfo(cycles = CYCLES_4, size = SIZE_16, allowedUsageTypes = {Memory}) -public class InitializeKlassNode extends DeoptimizingFixedWithNextNode implements Lowerable, SingleMemoryKill { - public static final NodeClass TYPE = NodeClass.create(InitializeKlassNode.class); - - @Input ValueNode value; - - public InitializeKlassNode(ValueNode value) { - super(TYPE, value.stamp(NodeView.DEFAULT)); - this.value = value; - } - - public ValueNode value() { - return value; - } - - @Override - public boolean canDeoptimize() { - return true; - } - - @Override - public LocationIdentity getKilledLocationIdentity() { - return LocationIdentity.any(); - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassStubCall.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassStubCall.java deleted file mode 100644 index 82611d3b6a53..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassStubCall.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.nodes.aot; - -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16; - -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.Canonicalizable; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; -import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; -import org.graalvm.compiler.hotspot.word.KlassPointer; -import org.graalvm.compiler.lir.LIRFrameState; -import org.graalvm.compiler.nodeinfo.InputType; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.DeoptimizingNode; -import org.graalvm.compiler.nodes.FrameState; -import org.graalvm.compiler.nodes.NodeView; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; -import org.graalvm.compiler.nodes.memory.SingleMemoryKill; -import org.graalvm.compiler.nodes.spi.LIRLowerable; -import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.compiler.word.Word; -import org.graalvm.word.LocationIdentity; - -import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.Value; - -/** - * A call to the VM via a regular stub. - */ -@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_16) -public class InitializeKlassStubCall extends AbstractMemoryCheckpoint implements LIRLowerable, Canonicalizable, DeoptimizingNode.DeoptBefore, SingleMemoryKill { - public static final NodeClass TYPE = NodeClass.create(InitializeKlassStubCall.class); - - @OptionalInput protected ValueNode value; - @Input protected ValueNode string; - @OptionalInput(InputType.State) protected FrameState stateBefore; - protected Constant constant; - - protected InitializeKlassStubCall(ValueNode value, ValueNode string) { - super(TYPE, value.stamp(NodeView.DEFAULT)); - this.value = value; - this.string = string; - } - - @NodeIntrinsic - public static native KlassPointer initializeKlass(KlassPointer value, Word string); - - @Override - public Node canonical(CanonicalizerTool tool) { - if (value != null) { - constant = GraphUtil.foldIfConstantAndRemove(this, value); - } - return this; - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - assert constant != null : "Expected the value to fold: " + value; - Value stringValue = gen.operand(string); - LIRFrameState fs = gen.state(this); - assert fs != null : "Frame state should be set"; - assert constant instanceof HotSpotMetaspaceConstant; - Value result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitKlassInitializationAndRetrieval(constant, stringValue, fs); - gen.setResult(this, result); - } - - @Override - public boolean canDeoptimize() { - return true; - } - - @Override - public LocationIdentity getKilledLocationIdentity() { - return LocationIdentity.any(); - } - - @Override - public FrameState stateBefore() { - return stateBefore; - } - - @Override - public void setStateBefore(FrameState f) { - updateUsages(stateBefore, f); - stateBefore = f; - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyFixedNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyFixedNode.java deleted file mode 100644 index 494bccae4caa..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyFixedNode.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.nodes.aot; - -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; - -import org.graalvm.compiler.core.common.PermanentBailoutException; -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.Canonicalizable; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; -import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; -import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; -import org.graalvm.compiler.hotspot.word.KlassPointer; -import org.graalvm.compiler.hotspot.word.MethodPointer; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.FixedWithNextNode; -import org.graalvm.compiler.nodes.NodeView; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.spi.LIRLowerable; -import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.compiler.nodes.util.GraphUtil; - -import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; -import jdk.vm.ci.hotspot.HotSpotObjectConstant; -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.Value; - -@NodeInfo(cycles = CYCLES_4, size = SIZE_1) -public class LoadConstantIndirectlyFixedNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable { - - public static final NodeClass TYPE = NodeClass.create(LoadConstantIndirectlyFixedNode.class); - - @OptionalInput protected ValueNode value; - protected Constant constant; - protected HotSpotConstantLoadAction action; - - public LoadConstantIndirectlyFixedNode(ValueNode value) { - super(TYPE, value.stamp(NodeView.DEFAULT)); - this.value = value; - this.constant = null; - this.action = HotSpotConstantLoadAction.RESOLVE; - } - - public LoadConstantIndirectlyFixedNode(ValueNode value, HotSpotConstantLoadAction action) { - super(TYPE, value.stamp(NodeView.DEFAULT)); - this.value = value; - this.constant = null; - this.action = action; - } - - @Override - public Node canonical(CanonicalizerTool tool) { - if (value != null) { - constant = GraphUtil.foldIfConstantAndRemove(this, value); - } - return this; - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - assert constant != null : "Expected the value to fold: " + value; - Value result; - if (constant instanceof HotSpotObjectConstant) { - result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadObjectAddress(constant); - } else if (constant instanceof HotSpotMetaspaceConstant) { - result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadMetaspaceAddress(constant, action); - } else { - throw new PermanentBailoutException("Unsupported constant type: " + constant); - } - gen.setResult(this, result); - } - - @NodeIntrinsic - public static native KlassPointer loadKlass(KlassPointer klassPointer, @ConstantNodeParameter HotSpotConstantLoadAction action); - - @NodeIntrinsic - public static native KlassPointer loadKlass(KlassPointer klassPointer); - - @NodeIntrinsic - public static native MethodPointer loadMethod(MethodPointer klassPointer); - - @NodeIntrinsic - public static native Object loadObject(Object object); - -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyNode.java deleted file mode 100644 index 44421747b93d..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyNode.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.nodes.aot; - -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; - -import org.graalvm.compiler.core.common.PermanentBailoutException; -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.Canonicalizable; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; -import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; -import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; -import org.graalvm.compiler.hotspot.word.KlassPointer; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.NodeView; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.calc.FloatingNode; -import org.graalvm.compiler.nodes.spi.LIRLowerable; -import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.compiler.nodes.util.GraphUtil; - -import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; -import jdk.vm.ci.hotspot.HotSpotObjectConstant; -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.Value; - -@NodeInfo(cycles = CYCLES_4, size = SIZE_1) -public class LoadConstantIndirectlyNode extends FloatingNode implements Canonicalizable, LIRLowerable { - - public static final NodeClass TYPE = NodeClass.create(LoadConstantIndirectlyNode.class); - - @OptionalInput protected ValueNode value; - protected Constant constant; - protected HotSpotConstantLoadAction action; - - public LoadConstantIndirectlyNode(ValueNode value) { - super(TYPE, value.stamp(NodeView.DEFAULT)); - this.value = value; - this.constant = null; - this.action = HotSpotConstantLoadAction.RESOLVE; - } - - public LoadConstantIndirectlyNode(ValueNode value, HotSpotConstantLoadAction action) { - super(TYPE, value.stamp(NodeView.DEFAULT)); - this.value = value; - this.constant = null; - this.action = action; - } - - @Override - public Node canonical(CanonicalizerTool tool) { - if (value != null) { - constant = GraphUtil.foldIfConstantAndRemove(this, value); - } - return this; - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - assert constant != null : "Expected the value to fold: " + value; - Value result; - if (constant instanceof HotSpotObjectConstant) { - result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadObjectAddress(constant); - } else if (constant instanceof HotSpotMetaspaceConstant) { - result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadMetaspaceAddress(constant, action); - } else { - throw new PermanentBailoutException("Unsupported constant type: " + constant); - } - gen.setResult(this, result); - } - - @NodeIntrinsic - public static native KlassPointer loadKlass(KlassPointer klassPointer, @ConstantNodeParameter HotSpotConstantLoadAction action); - - @NodeIntrinsic - public static native KlassPointer loadKlass(KlassPointer klassPointer); - - @NodeIntrinsic - public static native Object loadObject(Object object); - -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadMethodCountersIndirectlyNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadMethodCountersIndirectlyNode.java deleted file mode 100644 index 9e3dec055fb8..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadMethodCountersIndirectlyNode.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.nodes.aot; - -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4; - -import org.graalvm.compiler.core.common.PermanentBailoutException; -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.Canonicalizable; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; -import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; -import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; -import org.graalvm.compiler.hotspot.nodes.type.MethodCountersPointerStamp; -import org.graalvm.compiler.hotspot.word.MethodCountersPointer; -import org.graalvm.compiler.hotspot.word.MethodPointer; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.calc.FloatingNode; -import org.graalvm.compiler.nodes.spi.LIRLowerable; -import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.compiler.nodes.util.GraphUtil; - -import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.Value; - -@NodeInfo(cycles = CYCLES_4, size = SIZE_4) -public class LoadMethodCountersIndirectlyNode extends FloatingNode implements Canonicalizable, LIRLowerable { - - public static final NodeClass TYPE = NodeClass.create(LoadMethodCountersIndirectlyNode.class); - - @OptionalInput protected ValueNode value; - protected Constant constant; - - public LoadMethodCountersIndirectlyNode(ValueNode value) { - super(TYPE, MethodCountersPointerStamp.methodCounters()); - this.value = value; - this.constant = null; - } - - @Override - public Node canonical(CanonicalizerTool tool) { - if (value != null) { - constant = GraphUtil.foldIfConstantAndRemove(this, value); - } - return this; - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - assert constant != null : "Expected the value to fold: " + value; - Value result; - if (constant instanceof HotSpotMetaspaceConstant) { - result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadMetaspaceAddress(constant, HotSpotConstantLoadAction.LOAD_COUNTERS); - } else { - throw new PermanentBailoutException("Unsupported constant type: " + constant); - } - gen.setResult(this, result); - } - - @NodeIntrinsic - public static native MethodCountersPointer loadMethodCounters(MethodPointer methodPointer); -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadMethodCountersNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadMethodCountersNode.java deleted file mode 100644 index c5f13e5aa6b5..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadMethodCountersNode.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.nodes.aot; - -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4; - -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.graph.iterators.NodeIterable; -import org.graalvm.compiler.hotspot.nodes.type.MethodCountersPointerStamp; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.calc.FloatingNode; -import org.graalvm.compiler.nodes.spi.LIRLowerable; -import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; - -import jdk.vm.ci.meta.ResolvedJavaMethod; - -@NodeInfo(cycles = CYCLES_4, size = SIZE_4) -public class LoadMethodCountersNode extends FloatingNode implements LIRLowerable { - public static final NodeClass TYPE = NodeClass.create(LoadMethodCountersNode.class); - - ResolvedJavaMethod method; - - public LoadMethodCountersNode(ResolvedJavaMethod method) { - super(TYPE, MethodCountersPointerStamp.methodCountersNonNull()); - this.method = method; - } - - public ResolvedJavaMethod getMethod() { - return method; - } - - public static NodeIterable getLoadMethodCountersNodes(StructuredGraph graph) { - return graph.getNodes().filter(LoadMethodCountersNode.class); - } - - @Override - public void generate(NodeLIRBuilderTool generator) { - // TODO: With AOT we don't need this, as this node will be replaced. - // Implement later when profiling is needed in the JIT mode. - throw GraalError.unimplemented(); - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantNode.java deleted file mode 100644 index b10cb7e15ce4..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantNode.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.nodes.aot; - -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16; - -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode; -import org.graalvm.compiler.nodes.NodeView; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.spi.Lowerable; - -@NodeInfo(cycles = CYCLES_4, size = SIZE_16) -public class ResolveConstantNode extends DeoptimizingFixedWithNextNode implements Lowerable { - public static final NodeClass TYPE = NodeClass.create(ResolveConstantNode.class); - - @Input ValueNode value; - protected HotSpotConstantLoadAction action; - - public ResolveConstantNode(ValueNode value, HotSpotConstantLoadAction action) { - super(TYPE, value.stamp(NodeView.DEFAULT)); - this.value = value; - this.action = action; - } - - public ResolveConstantNode(ValueNode value) { - super(TYPE, value.stamp(NodeView.DEFAULT)); - this.value = value; - this.action = HotSpotConstantLoadAction.RESOLVE; - } - - public ValueNode value() { - return value; - } - - public HotSpotConstantLoadAction action() { - return action; - } - - @Override - public boolean canDeoptimize() { - return true; - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantStubCall.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantStubCall.java deleted file mode 100644 index fc0e2dcfb33a..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantStubCall.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.nodes.aot; - -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16; - -import org.graalvm.compiler.core.common.PermanentBailoutException; -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.Canonicalizable; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; -import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; -import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; -import org.graalvm.compiler.hotspot.nodes.DeoptimizingStubCall; -import org.graalvm.compiler.hotspot.word.KlassPointer; -import org.graalvm.compiler.lir.LIRFrameState; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.NodeView; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.spi.LIRLowerable; -import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.compiler.word.Word; - -import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; -import jdk.vm.ci.hotspot.HotSpotObjectConstant; -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.Value; - -/** - * A call to the VM via a regular stub. - */ -@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_16) -public class ResolveConstantStubCall extends DeoptimizingStubCall implements Canonicalizable, LIRLowerable { - public static final NodeClass TYPE = NodeClass.create(ResolveConstantStubCall.class); - - @OptionalInput protected ValueNode value; - @Input protected ValueNode string; - protected Constant constant; - protected HotSpotConstantLoadAction action; - - public ResolveConstantStubCall(ValueNode value, ValueNode string) { - super(TYPE, value.stamp(NodeView.DEFAULT)); - this.value = value; - this.string = string; - this.action = HotSpotConstantLoadAction.RESOLVE; - } - - public ResolveConstantStubCall(ValueNode value, ValueNode string, HotSpotConstantLoadAction action) { - super(TYPE, value.stamp(NodeView.DEFAULT)); - this.value = value; - this.string = string; - this.action = action; - } - - @NodeIntrinsic - public static native Object resolveObject(Object value, Object symbol); - - @NodeIntrinsic - public static native KlassPointer resolveKlass(KlassPointer value, Word symbol); - - @NodeIntrinsic - public static native KlassPointer resolveKlass(KlassPointer value, Word symbol, @ConstantNodeParameter HotSpotConstantLoadAction action); - - @Override - public Node canonical(CanonicalizerTool tool) { - if (value != null) { - constant = GraphUtil.foldIfConstantAndRemove(this, value); - } - return this; - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - assert constant != null : "Expected the value to fold: " + value; - Value stringValue = gen.operand(string); - Value result; - LIRFrameState fs = gen.state(this); - assert fs != null : "The stateAfter is null"; - if (constant instanceof HotSpotObjectConstant) { - result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitObjectConstantRetrieval(constant, stringValue, fs); - } else if (constant instanceof HotSpotMetaspaceConstant) { - if (action == HotSpotConstantLoadAction.RESOLVE) { - result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitMetaspaceConstantRetrieval(constant, stringValue, fs); - } else { - assert action == HotSpotConstantLoadAction.INITIALIZE; - result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitKlassInitializationAndRetrieval(constant, stringValue, fs); - } - } else { - throw new PermanentBailoutException("Unsupported constant type: " + constant); - } - gen.setResult(this, result); - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicConstantNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicConstantNode.java deleted file mode 100644 index 677882aca627..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicConstantNode.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.nodes.aot; - -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16; - -import org.graalvm.compiler.core.common.type.Stamp; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodeinfo.InputType; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.memory.SingleMemoryKill; -import org.graalvm.compiler.nodes.spi.Lowerable; -import org.graalvm.word.LocationIdentity; - -@NodeInfo(cycles = CYCLES_4, size = SIZE_16, allowedUsageTypes = {InputType.Memory}) -public class ResolveDynamicConstantNode extends DeoptimizingFixedWithNextNode implements Lowerable, SingleMemoryKill { - public static final NodeClass TYPE = NodeClass.create(ResolveDynamicConstantNode.class); - - @Input ValueNode value; - - public ResolveDynamicConstantNode(Stamp valueStamp, ValueNode value) { - super(TYPE, valueStamp); - this.value = value; - } - - public ValueNode value() { - return value; - } - - @Override - public boolean canDeoptimize() { - return true; - } - - @Override - public LocationIdentity getKilledLocationIdentity() { - return LocationIdentity.any(); - } - -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicStubCall.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicStubCall.java deleted file mode 100644 index 6d4b1d81881a..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicStubCall.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.nodes.aot; - -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16; - -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.Canonicalizable; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; -import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; -import org.graalvm.compiler.lir.LIRFrameState; -import org.graalvm.compiler.nodeinfo.InputType; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.DeoptimizingNode; -import org.graalvm.compiler.nodes.FrameState; -import org.graalvm.compiler.nodes.NodeView; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.spi.LIRLowerable; -import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; -import org.graalvm.compiler.nodes.memory.SingleMemoryKill; -import org.graalvm.word.LocationIdentity; - -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.Value; - -/** - * A call to the VM via a regular stub. - */ -@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_16) -public class ResolveDynamicStubCall extends AbstractMemoryCheckpoint implements LIRLowerable, Canonicalizable, DeoptimizingNode.DeoptBefore, SingleMemoryKill { - public static final NodeClass TYPE = NodeClass.create(ResolveDynamicStubCall.class); - - @OptionalInput protected ValueNode value; - @OptionalInput(InputType.State) protected FrameState stateBefore; - protected Constant constant; - - public ResolveDynamicStubCall(ValueNode value) { - super(TYPE, value.stamp(NodeView.DEFAULT)); - this.value = value; - } - - @NodeIntrinsic - public static native Object resolveInvoke(Object value); - - @Override - public Node canonical(CanonicalizerTool tool) { - if (value != null) { - constant = GraphUtil.foldIfConstantAndRemove(this, value); - } - return this; - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - assert constant != null : "Expected the value to fold: " + value; - Value result; - LIRFrameState fs = gen.state(this); - assert fs != null : "The stateAfter is null"; - result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitResolveDynamicInvoke(constant, fs); - gen.setResult(this, result); - } - - @Override - public boolean canDeoptimize() { - return true; - } - - @Override - public LocationIdentity getKilledLocationIdentity() { - return LocationIdentity.any(); - } - - @Override - public FrameState stateBefore() { - return stateBefore; - } - - @Override - public void setStateBefore(FrameState f) { - updateUsages(stateBefore, f); - stateBefore = f; - } - - @Override - public void markDeleted() { - throw GraalError.shouldNotReachHere("ResolveDynamicStubCall node deleted"); - } - -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveMethodAndLoadCountersNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveMethodAndLoadCountersNode.java deleted file mode 100644 index 4937a94f97c1..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveMethodAndLoadCountersNode.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.nodes.aot; - -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16; - -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.hotspot.nodes.type.MethodCountersPointerStamp; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.spi.Lowerable; - -import jdk.vm.ci.meta.ResolvedJavaMethod; - -@NodeInfo(cycles = CYCLES_4, size = SIZE_16) -public class ResolveMethodAndLoadCountersNode extends DeoptimizingFixedWithNextNode implements Lowerable { - public static final NodeClass TYPE = NodeClass.create(ResolveMethodAndLoadCountersNode.class); - - ResolvedJavaMethod method; - @Input ValueNode hub; - - public ResolveMethodAndLoadCountersNode(ResolvedJavaMethod method, ValueNode hub) { - super(TYPE, MethodCountersPointerStamp.methodCountersNonNull()); - this.method = method; - this.hub = hub; - } - - public ResolvedJavaMethod getMethod() { - return method; - } - - public ValueNode getHub() { - return hub; - } - - @Override - public boolean canDeoptimize() { - return true; - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveMethodAndLoadCountersStubCall.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveMethodAndLoadCountersStubCall.java deleted file mode 100644 index a880291aa278..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveMethodAndLoadCountersStubCall.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.nodes.aot; - -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16; - -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.Canonicalizable; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; -import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; -import org.graalvm.compiler.hotspot.nodes.DeoptimizingStubCall; -import org.graalvm.compiler.hotspot.nodes.type.MethodCountersPointerStamp; -import org.graalvm.compiler.hotspot.word.KlassPointer; -import org.graalvm.compiler.hotspot.word.MethodCountersPointer; -import org.graalvm.compiler.hotspot.word.MethodPointer; -import org.graalvm.compiler.lir.LIRFrameState; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.spi.LIRLowerable; -import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.compiler.word.Word; - -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.Value; - -/** - * A call to the VM via a regular stub. - */ -@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_16) -public class ResolveMethodAndLoadCountersStubCall extends DeoptimizingStubCall implements Canonicalizable, LIRLowerable { - public static final NodeClass TYPE = NodeClass.create(ResolveMethodAndLoadCountersStubCall.class); - - @OptionalInput protected ValueNode method; - @Input protected ValueNode klassHint; - @Input protected ValueNode methodDescription; - protected Constant methodConstant; - - public ResolveMethodAndLoadCountersStubCall(ValueNode method, ValueNode klassHint, ValueNode methodDescription) { - super(TYPE, MethodCountersPointerStamp.methodCountersNonNull()); - this.klassHint = klassHint; - this.method = method; - this.methodDescription = methodDescription; - } - - @NodeIntrinsic - public static native MethodCountersPointer resolveMethodAndLoadCounters(MethodPointer method, KlassPointer klassHint, Word methodDescription); - - @Override - public Node canonical(CanonicalizerTool tool) { - if (method != null) { - methodConstant = GraphUtil.foldIfConstantAndRemove(this, method); - } - return this; - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - assert methodConstant != null : "Expected method to fold: " + method; - - Value methodDescriptionValue = gen.operand(methodDescription); - Value klassHintValue = gen.operand(klassHint); - LIRFrameState fs = gen.state(this); - assert fs != null : "The stateAfter is null"; - - Value result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitResolveMethodAndLoadCounters(methodConstant, klassHintValue, methodDescriptionValue, fs); - - gen.setResult(this, result); - } - -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileBranchNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileBranchNode.java deleted file mode 100644 index 55e059ebd1ac..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileBranchNode.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.nodes.profiling; - -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.graph.iterators.NodeIterable; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.calc.ConditionalNode; - -import jdk.vm.ci.meta.ResolvedJavaMethod; - -@NodeInfo -public class ProfileBranchNode extends ProfileWithNotificationNode { - public static final NodeClass TYPE = NodeClass.create(ProfileBranchNode.class); - - @OptionalInput ValueNode branchCondition; - protected int bci; - protected int targetBci; - - public ProfileBranchNode(ResolvedJavaMethod method, int freqLog, int probabilityLog, ConditionalNode branchCondition, int bci, int targetBci) { - super(TYPE, method, freqLog, probabilityLog); - assert targetBci <= bci; - this.branchCondition = branchCondition; - this.bci = bci; - this.targetBci = targetBci; - } - - public ProfileBranchNode(ResolvedJavaMethod method, int freqLog, int probabilityLog, int bci, int targetBci) { - super(TYPE, method, freqLog, probabilityLog); - assert targetBci <= bci; - this.branchCondition = null; - this.bci = bci; - this.targetBci = targetBci; - } - - public int bci() { - return bci; - } - - public int targetBci() { - return targetBci; - } - - public ValueNode branchCondition() { - return branchCondition; - } - - public boolean hasCondition() { - return branchCondition != null; - } - - @Override - protected boolean canBeMergedWith(ProfileNode p) { - if (p instanceof ProfileBranchNode) { - ProfileBranchNode that = (ProfileBranchNode) p; - return this.method.equals(that.method) && this.bci == that.bci; - } - return false; - } - - /** - * Gathers all the {@link ProfileBranchNode}s that are inputs to the - * {@linkplain StructuredGraph#getNodes() live nodes} in a given graph. - */ - public static NodeIterable getProfileBranchNodes(StructuredGraph graph) { - return graph.getNodes().filter(ProfileBranchNode.class); - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileInvokeNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileInvokeNode.java deleted file mode 100644 index 40c8999b17d0..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileInvokeNode.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.nodes.profiling; - -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.graph.iterators.NodeIterable; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.StructuredGraph; - -import jdk.vm.ci.meta.ResolvedJavaMethod; - -@NodeInfo -public class ProfileInvokeNode extends ProfileWithNotificationNode { - public static final NodeClass TYPE = NodeClass.create(ProfileInvokeNode.class); - - public ProfileInvokeNode(ResolvedJavaMethod method, int freqLog, int probabilityLog) { - super(TYPE, method, freqLog, probabilityLog); - } - - @Override - protected boolean canBeMergedWith(ProfileNode p) { - if (p instanceof ProfileInvokeNode) { - ProfileInvokeNode that = (ProfileInvokeNode) p; - return this.method.equals(that.method); - } - return false; - } - - /** - * Gathers all the {@link ProfileInvokeNode}s that are inputs to the - * {@linkplain StructuredGraph#getNodes() live nodes} in a given graph. - */ - public static NodeIterable getProfileInvokeNodes(StructuredGraph graph) { - return graph.getNodes().filter(ProfileInvokeNode.class); - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileNode.java deleted file mode 100644 index 1141991169fb..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileNode.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.nodes.profiling; - -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; -import static org.graalvm.compiler.nodes.util.GraphUtil.removeFixedWithUnusedInputs; - -import org.graalvm.compiler.core.common.type.StampFactory; -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.graph.iterators.NodeIterable; -import org.graalvm.compiler.nodes.spi.Simplifiable; -import org.graalvm.compiler.nodes.spi.SimplifierTool; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.AbstractMergeNode; -import org.graalvm.compiler.nodes.ControlSplitNode; -import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.memory.SingleMemoryKill; -import org.graalvm.compiler.nodes.spi.Lowerable; -import org.graalvm.compiler.options.Option; -import org.graalvm.compiler.options.OptionKey; -import org.graalvm.compiler.options.OptionType; -import org.graalvm.word.LocationIdentity; - -import jdk.vm.ci.meta.ResolvedJavaMethod; - -@NodeInfo(cycles = CYCLES_IGNORED, cyclesRationale = "profiling should be ignored", size = SIZE_IGNORED, sizeRationale = "profiling should be ignored") -public abstract class ProfileNode extends DeoptimizingFixedWithNextNode implements SingleMemoryKill, Simplifiable, Lowerable { - public static class Options { - @Option(help = "Control probabilistic profiling on AMD64", type = OptionType.Expert)// - public static final OptionKey ProbabilisticProfiling = new OptionKey<>(true); - } - - public static final NodeClass TYPE = NodeClass.create(ProfileNode.class); - - protected ResolvedJavaMethod method; - - // Only used if ProbabilisticProfiling == true and may be ignored by lowerer. - @OptionalInput protected ValueNode random; - - // Logarithm base 2 of the profile probability. - protected int probabilityLog; - - // Step value to add to the profile counter. - protected int step; - - protected ProfileNode(NodeClass c, ResolvedJavaMethod method, int probabilityLog) { - super(c, StampFactory.forVoid()); - this.method = method; - this.probabilityLog = probabilityLog; - this.step = 1; - } - - public ProfileNode(ResolvedJavaMethod method, int probabilityLog) { - this(TYPE, method, probabilityLog); - } - - @Override - public boolean canDeoptimize() { - return true; - } - - public ResolvedJavaMethod getProfiledMethod() { - return method; - } - - public ValueNode getRandom() { - return random; - } - - public void setRandom(ValueNode r) { - updateUsages(random, r); - this.random = r; - } - - public int getStep() { - return step; - } - - public void setStep(int s) { - step = s; - } - - /** - * Get the logarithm base 2 of the profile probability. - */ - public int getProbabilityLog() { - return probabilityLog; - } - - /** - * Gathers all the {@link ProfileNode}s that are inputs to the - * {@linkplain StructuredGraph#getNodes() live nodes} in a given graph. - */ - public static NodeIterable getProfileNodes(StructuredGraph graph) { - return graph.getNodes().filter(ProfileNode.class); - } - - protected abstract boolean canBeMergedWith(ProfileNode p); - - @Override - public void simplify(SimplifierTool tool) { - for (Node p = predecessor(); p != null; p = p.predecessor()) { - // Terminate search when we hit a control split or merge. - if (p instanceof ControlSplitNode || p instanceof AbstractMergeNode) { - break; - } - if (p instanceof ProfileNode) { - ProfileNode that = (ProfileNode) p; - if (this.canBeMergedWith(that)) { - that.setStep(this.getStep() + that.getStep()); - removeFixedWithUnusedInputs(this); - tool.addToWorkList(that); - break; - } - } - } - } - - @Override - public LocationIdentity getKilledLocationIdentity() { - return LocationIdentity.any(); - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileWithNotificationNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileWithNotificationNode.java deleted file mode 100644 index 078f242878f4..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileWithNotificationNode.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.nodes.profiling; - -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodeinfo.NodeInfo; - -import jdk.vm.ci.meta.ResolvedJavaMethod; - -@NodeInfo -public abstract class ProfileWithNotificationNode extends ProfileNode { - public static final NodeClass TYPE = NodeClass.create(ProfileWithNotificationNode.class); - - protected int freqLog; - - protected ProfileWithNotificationNode(NodeClass c, ResolvedJavaMethod method, int freqLog, int probabilityLog) { - super(c, method, probabilityLog); - this.freqLog = freqLog; - } - - public ProfileWithNotificationNode(ResolvedJavaMethod method, int freqLog, int probabilityLog) { - super(TYPE, method, probabilityLog); - this.freqLog = freqLog; - } - - /** - * Get the logarithm base 2 of the notification frequency. - */ - public int getNotificationFreqLog() { - return freqLog; - } - - /** - * Set the logarithm base 2 of the notification frequency. - */ - public void setNotificationFreqLog(int freqLog) { - assert freqLog < 32; - this.freqLog = freqLog; - } - - public void setNotificationOff() { - setNotificationFreqLog(-1); - } - -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/RandomSeedNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/RandomSeedNode.java deleted file mode 100644 index 48258b541e30..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/RandomSeedNode.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.graalvm.compiler.hotspot.nodes.profiling; - -import jdk.vm.ci.meta.Value; - -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; - -import org.graalvm.compiler.core.common.type.StampFactory; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.calc.FloatingNode; -import org.graalvm.compiler.nodes.spi.LIRLowerable; -import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; - -@NodeInfo(cycles = CYCLES_1, size = SIZE_1) -public class RandomSeedNode extends FloatingNode implements LIRLowerable { - public static final NodeClass TYPE = NodeClass.create(RandomSeedNode.class); - - public RandomSeedNode() { - super(TYPE, StampFactory.intValue()); - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - Value result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitRandomSeed(); - gen.setResult(this, result); - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/AheadOfTimeVerificationPhase.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/AheadOfTimeVerificationPhase.java deleted file mode 100644 index 29e96a7a78f8..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/AheadOfTimeVerificationPhase.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.phases; - -import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes; - -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.spi.CoreProviders; -import org.graalvm.compiler.nodes.type.StampTool; -import org.graalvm.compiler.phases.VerifyPhase; - -import jdk.vm.ci.hotspot.HotSpotObjectConstant; -import jdk.vm.ci.meta.JavaKind; - -/** - * Checks for {@link #isIllegalObjectConstant(ConstantNode) illegal} object constants in a graph - * processed for AOT compilation. - * - * @see LoadJavaMirrorWithKlassPhase - */ -public class AheadOfTimeVerificationPhase extends VerifyPhase { - - @Override - protected void verify(StructuredGraph graph, CoreProviders context) { - for (ConstantNode node : getConstantNodes(graph)) { - if (isIllegalObjectConstant(node)) { - throw new VerificationError("illegal object constant: " + node); - } - } - } - - public static boolean isIllegalObjectConstant(ConstantNode node) { - return isObject(node) && - !isNullReference(node) && - !isInternedString(node) && - !isDirectMethodHandle(node) && - !isBoundMethodHandle(node) && - !isVarHandle(node); - } - - private static boolean isObject(ConstantNode node) { - return node.getStackKind() == JavaKind.Object; - } - - private static boolean isNullReference(ConstantNode node) { - return isObject(node) && node.isNullConstant(); - } - - private static boolean isDirectMethodHandle(ConstantNode node) { - String typeName = StampTool.typeOrNull(node).getName(); - if (!isObject(node)) { - return false; - } - - switch (typeName) { - case "Ljava/lang/invoke/DirectMethodHandle;": - case "Ljava/lang/invoke/DirectMethodHandle$StaticAccessor;": - case "Ljava/lang/invoke/DirectMethodHandle$Accessor;": - case "Ljava/lang/invoke/DirectMethodHandle$Constructor;": - case "Ljava/lang/invoke/DirectMethodHandle$Special;": - case "Ljava/lang/invoke/DirectMethodHandle$Interface;": - return true; - default: - return false; - } - } - - private static boolean isBoundMethodHandle(ConstantNode node) { - if (!isObject(node)) { - return false; - } - return StampTool.typeOrNull(node).getName().startsWith("Ljava/lang/invoke/BoundMethodHandle"); - } - - private static boolean isVarHandle(ConstantNode node) { - if (!isObject(node)) { - return false; - } - String name = StampTool.typeOrNull(node).getName(); - return name.equals("Ljava/lang/invoke/VarHandle$AccessDescriptor;"); - } - - private static boolean isInternedString(ConstantNode node) { - if (!isObject(node)) { - return false; - } - - HotSpotObjectConstant c = (HotSpotObjectConstant) node.asConstant(); - return c.isInternedString(); - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/LoadJavaMirrorWithKlassPhase.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/LoadJavaMirrorWithKlassPhase.java deleted file mode 100644 index 70657aff2e98..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/LoadJavaMirrorWithKlassPhase.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.phases; - -import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes; -import static org.graalvm.compiler.nodes.NamedLocationIdentity.FINAL_LOCATION; - -import org.graalvm.compiler.core.common.CompressEncoding; -import org.graalvm.compiler.core.common.type.AbstractObjectStamp; -import org.graalvm.compiler.core.common.type.Stamp; -import org.graalvm.compiler.core.common.type.StampFactory; -import org.graalvm.compiler.core.common.type.TypeReference; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.hotspot.nodes.HotSpotCompressionNode; -import org.graalvm.compiler.hotspot.nodes.type.HotSpotNarrowOopStamp; -import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; -import org.graalvm.compiler.hotspot.replacements.HubGetClassNode; -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.memory.FloatingReadNode; -import org.graalvm.compiler.nodes.memory.address.AddressNode; -import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; -import org.graalvm.compiler.nodes.spi.CoreProviders; -import org.graalvm.compiler.phases.BasePhase; -import org.graalvm.compiler.phases.common.LoweringPhase; - -import jdk.vm.ci.hotspot.HotSpotObjectConstant; -import jdk.vm.ci.hotspot.HotSpotResolvedJavaField; -import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; -import jdk.vm.ci.hotspot.HotSpotResolvedPrimitiveType; -import jdk.vm.ci.meta.ConstantReflectionProvider; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaType; - -/** - * For AOT compilation we aren't allowed to use a {@link Class} reference ({@code javaMirror}) - * directly. Instead the {@link Class} reference should be obtained from the {@code Klass} object. - * The reason for this is, that in Class Data Sharing (CDS) a {@code Klass} object is mapped to a - * fixed address in memory, but the {@code javaMirror} is not (which lives in the Java heap). - * - * Lowering can introduce new {@link ConstantNode}s containing a {@link Class} reference, thus this - * phase must be applied after {@link LoweringPhase}. - * - * @see AheadOfTimeVerificationPhase - */ -public class LoadJavaMirrorWithKlassPhase extends BasePhase { - - private final CompressEncoding oopEncoding; - - public LoadJavaMirrorWithKlassPhase(GraalHotSpotVMConfig config) { - this.oopEncoding = config.useCompressedOops ? config.getOopEncoding() : null; - } - - private ValueNode getClassConstantReplacement(StructuredGraph graph, CoreProviders context, JavaConstant constant) { - if (constant instanceof HotSpotObjectConstant) { - ConstantReflectionProvider constantReflection = context.getConstantReflection(); - ResolvedJavaType type = constantReflection.asJavaType(constant); - if (type != null) { - MetaAccessProvider metaAccess = context.getMetaAccess(); - Stamp stamp = StampFactory.objectNonNull(TypeReference.createExactTrusted(metaAccess.lookupJavaType(Class.class))); - - if (type instanceof HotSpotResolvedObjectType) { - ConstantNode klass = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), ((HotSpotResolvedObjectType) type).klass(), metaAccess, graph); - ValueNode getClass = graph.unique(new HubGetClassNode(metaAccess, klass)); - - if (((HotSpotObjectConstant) constant).isCompressed()) { - return HotSpotCompressionNode.compress(getClass, oopEncoding); - } else { - return getClass; - } - } else { - /* - * Primitive classes are more difficult since they don't have a corresponding - * Klass* so get them from Class.TYPE for the java box type. - */ - HotSpotResolvedPrimitiveType primitive = (HotSpotResolvedPrimitiveType) type; - ResolvedJavaType boxingClass = metaAccess.lookupJavaType(primitive.getJavaKind().toBoxedJavaClass()); - ConstantNode clazz = ConstantNode.forConstant(context.getConstantReflection().asJavaClass(boxingClass), metaAccess, graph); - HotSpotResolvedJavaField[] a = (HotSpotResolvedJavaField[]) boxingClass.getStaticFields(); - HotSpotResolvedJavaField typeField = null; - for (HotSpotResolvedJavaField f : a) { - if (f.getName().equals("TYPE")) { - typeField = f; - break; - } - } - if (typeField == null) { - throw new GraalError("Can't find TYPE field in class"); - } - - if (oopEncoding != null) { - stamp = HotSpotNarrowOopStamp.compressed((AbstractObjectStamp) stamp, oopEncoding); - } - AddressNode address = graph.unique(new OffsetAddressNode(clazz, ConstantNode.forLong(typeField.getOffset(), graph))); - ValueNode read = graph.unique(new FloatingReadNode(address, FINAL_LOCATION, null, stamp)); - - if (oopEncoding == null || ((HotSpotObjectConstant) constant).isCompressed()) { - return read; - } else { - return HotSpotCompressionNode.uncompress(read, oopEncoding); - } - } - } - } - return null; - } - - @Override - protected void run(StructuredGraph graph, CoreProviders context) { - for (ConstantNode node : getConstantNodes(graph)) { - JavaConstant constant = node.asJavaConstant(); - ValueNode freadNode = getClassConstantReplacement(graph, context, constant); - if (freadNode != null) { - node.replace(graph, freadNode); - } - } - } - - @Override - public float codeSizeIncrease() { - return 2.5f; - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/AOTInliningPolicy.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/AOTInliningPolicy.java deleted file mode 100644 index 95e57ba1143d..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/AOTInliningPolicy.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.phases.aot; - -import static org.graalvm.compiler.core.common.GraalOptions.InlineEverything; -import static org.graalvm.compiler.core.common.GraalOptions.TrivialInliningSize; - -import java.util.Map; - -import org.graalvm.compiler.core.common.GraalOptions; -import org.graalvm.compiler.nodes.Invoke; -import org.graalvm.compiler.nodes.spi.Replacements; -import org.graalvm.compiler.options.Option; -import org.graalvm.compiler.options.OptionKey; -import org.graalvm.compiler.options.OptionType; -import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.phases.common.inlining.InliningUtil; -import org.graalvm.compiler.phases.common.inlining.info.InlineInfo; -import org.graalvm.compiler.phases.common.inlining.policy.GreedyInliningPolicy; -import org.graalvm.compiler.phases.common.inlining.policy.InliningPolicy; -import org.graalvm.compiler.phases.common.inlining.walker.MethodInvocation; - -import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; - -public class AOTInliningPolicy extends GreedyInliningPolicy { - public static class Options { - // @formatter:off - @Option(help = "", type = OptionType.Expert) - public static final OptionKey AOTInliningDepthToSizeRate = new OptionKey<>(2.5); - @Option(help = "", type = OptionType.Expert) - public static final OptionKey AOTInliningSizeMaximum = new OptionKey<>(300); - @Option(help = "", type = OptionType.Expert) - public static final OptionKey AOTInliningSizeMinimum = new OptionKey<>(50); - // @formatter:on - } - - public AOTInliningPolicy(Map hints) { - super(hints); - } - - protected double maxInliningSize(int inliningDepth, OptionValues options) { - return Math.max(Options.AOTInliningSizeMaximum.getValue(options) / (inliningDepth * Options.AOTInliningDepthToSizeRate.getValue(options)), Options.AOTInliningSizeMinimum.getValue(options)); - } - - @Override - public Decision isWorthInlining(Replacements replacements, MethodInvocation invocation, InlineInfo calleeInfo, int inliningDepth, boolean fullyProcessed) { - OptionValues options = calleeInfo.graph().getOptions(); - final boolean isTracing = GraalOptions.TraceInlining.getValue(options) || calleeInfo.graph().getDebug().hasCompilationListener(); - - final InlineInfo info = invocation.callee(); - - for (int i = 0; i < info.numberOfMethods(); ++i) { - HotSpotResolvedObjectType t = (HotSpotResolvedObjectType) info.methodAt(i).getDeclaringClass(); - if (t.getFingerprint() == 0) { - return InliningPolicy.Decision.NO.withReason(isTracing, "missing fingerprint"); - } - } - - final double probability = invocation.probability(); - final double relevance = invocation.relevance(); - - if (InlineEverything.getValue(options)) { - InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything"); - return InliningPolicy.Decision.YES.withReason(isTracing, "inline everything"); - } - - if (isIntrinsic(replacements, info)) { - InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic"); - return InliningPolicy.Decision.YES.withReason(isTracing, "intrinsic"); - } - - if (info.shouldInline()) { - InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining"); - return InliningPolicy.Decision.YES.withReason(isTracing, "forced inlining"); - } - - double inliningBonus = getInliningBonus(info); - int nodes = info.determineNodeCount(); - - if (nodes < TrivialInliningSize.getValue(options) * inliningBonus) { - InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes); - return InliningPolicy.Decision.YES.withReason(isTracing, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes); - } - - double maximumNodes = computeMaximumSize(relevance, (int) (maxInliningSize(inliningDepth, options) * inliningBonus)); - if (nodes <= maximumNodes) { - InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus, - nodes, maximumNodes); - return InliningPolicy.Decision.YES.withReason(isTracing, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus, - nodes, maximumNodes); - } - - InliningUtil.traceNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes); - return InliningPolicy.Decision.NO.withReason(isTracing, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes); - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java deleted file mode 100644 index eb8d222f0ce0..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.phases.aot; - -import static org.graalvm.util.CollectionsUtil.anyMatch; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.graalvm.collections.EconomicSet; -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; -import org.graalvm.compiler.nodes.AbstractMergeNode; -import org.graalvm.compiler.nodes.FixedNode; -import org.graalvm.compiler.nodes.FixedWithNextNode; -import org.graalvm.compiler.nodes.Invoke; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.spi.CoreProviders; -import org.graalvm.compiler.phases.BasePhase; -import org.graalvm.compiler.phases.graph.MergeableState; -import org.graalvm.compiler.phases.graph.PostOrderNodeIterator; - -import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.ResolvedJavaType; - -public class EliminateRedundantInitializationPhase extends BasePhase { - /** - * Find each {@link Invoke} that has a corresponding {@link InitializeKlassNode}. These - * {@link InitializeKlassNode} are redundant and are removed. - */ - private static void removeInitsAtStaticCalls(StructuredGraph graph) { - for (Invoke invoke : graph.getInvokes()) { - Node classInit = invoke.classInit(); - if (classInit != null) { - classInit.replaceAtUsages(null); - graph.removeFixed((FixedWithNextNode) classInit); - } - } - } - - /** - * Remove redundant {@link InitializeKlassNode} or {@link ResolveConstantNode} instances from - * the graph. - * - * @param graph the program graph - */ - private static void removeRedundantInits(StructuredGraph graph) { - // Find and remove redundant nodes from the graph. - List redundantNodes = findRedundantInits(graph); - for (FixedWithNextNode n : redundantNodes) { - graph.removeFixed(n); - } - } - - /** - * Find {@link InitializeKlassNode} and {@link ResolveConstantNode} instances that can be - * removed because there is an existing dominating node. - * - * @param graph the program graph - */ - private static List findRedundantInits(StructuredGraph graph) { - EliminateRedundantInitializationIterator i = new EliminateRedundantInitializationIterator(graph.start(), new InitializedTypes()); - i.apply(); - return i.getRedundantNodes(); - } - - /** - * State for {@link EliminateRedundantInitializationIterator}. - */ - private static class InitializedTypes extends MergeableState implements Cloneable { - private EconomicSet types; - - InitializedTypes() { - types = EconomicSet.create(); - } - - private InitializedTypes(EconomicSet types) { - this.types = types; - } - - @Override - public InitializedTypes clone() { - return new InitializedTypes(EconomicSet.create(types)); - } - - public boolean contains(ResolvedJavaType type) { - if (type.isInterface() || type.isArray()) { - // Check for exact match for interfaces - return types.contains(type); - } - // For other types see if there is the same type or a subtype - return anyMatch(types, t -> type.isAssignableFrom(t)); - } - - public void add(ResolvedJavaType type) { - types.add(type); - } - - /** - * Merge two given types. Interfaces and arrays have to be the same to merge successfully. - * For other types the answer is the LCA. - * - * @param a initialized type - * @param b initialized type - * @return lowest common type that is initialized if either a or b are initialized, null if - * no such type exists. - */ - private static ResolvedJavaType merge(ResolvedJavaType a, ResolvedJavaType b) { - // We want exact match for interfaces or arrays - if (a.isInterface() || b.isInterface() || a.isArray() || b.isArray()) { - if (a.equals(b)) { - return a; - } else { - return null; - } - } else { - // And LCA for other types - ResolvedJavaType c = a.findLeastCommonAncestor(b); - if (c.isJavaLangObject()) { - // Not a very useful type, always initialized, don't pollute the sets. - return null; - } - return c; - } - } - - /** - * Merge two sets of types. Essentially a computation of the LCA for each element of the - * cartesian product of the input sets. Interfaces have to match exactly. - * - * @param a set of initialized types - * @param b set of initialized types - * @return set of common types that would be initialized if types in either a or b are - * initialized - */ - private static EconomicSet merge(EconomicSet a, EconomicSet b) { - EconomicSet c = EconomicSet.create(); - for (ResolvedJavaType ta : a) { - for (ResolvedJavaType tb : b) { - ResolvedJavaType tc = merge(ta, tb); - if (tc != null) { - c.add(tc); - if (tc.isInterface() || tc.isArray()) { - // Interfaces and arrays are not going merge with anything else, so bail - // out early. - break; - } - } - } - } - return c; - } - - @Override - public boolean merge(AbstractMergeNode merge, List withStates) { - for (InitializedTypes ts : withStates) { - types = merge(types, ts.types); - } - return true; - } - - protected static String toString(EconomicSet types) { - StringBuilder b = new StringBuilder(); - b.append("["); - Iterator i = types.iterator(); - while (i.hasNext()) { - ResolvedJavaType t = i.next(); - b.append(t.toString()); - if (i.hasNext()) { - b.append(","); - } - } - b.append("]"); - return b.toString(); - } - - @Override - public String toString() { - return toString(types); - } - } - - /** - * Do data flow analysis of class initializations and array resolutions. Collect redundant - * nodes. - */ - private static class EliminateRedundantInitializationIterator extends PostOrderNodeIterator { - private List redundantNodes = new ArrayList<>(); - - public List getRedundantNodes() { - return redundantNodes; - } - - EliminateRedundantInitializationIterator(FixedNode start, InitializedTypes initialState) { - super(start, initialState); - } - - private void processType(FixedWithNextNode node, Constant c) { - HotSpotMetaspaceConstant klass = (HotSpotMetaspaceConstant) c; - ResolvedJavaType t = klass.asResolvedJavaType(); - if (t != null) { - if (state.contains(t)) { - redundantNodes.add(node); - } else { - state.add(t); - } - } - } - - @Override - protected void node(FixedNode node) { - if (node instanceof InitializeKlassNode) { - InitializeKlassNode i = (InitializeKlassNode) node; - if (i.value().isConstant()) { - processType(i, i.value().asConstant()); - } - } else if (node instanceof ResolveConstantNode) { - ResolveConstantNode r = (ResolveConstantNode) node; - if (r.hasNoUsages()) { - if (r.value().isConstant()) { - processType(r, r.value().asConstant()); - } - } - } - } - - } - - @Override - protected void run(StructuredGraph graph, CoreProviders context) { - removeInitsAtStaticCalls(graph); - removeRedundantInits(graph); - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java deleted file mode 100644 index 9872c70c1705..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java +++ /dev/null @@ -1,602 +0,0 @@ -/* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.phases.aot; - -import static org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph.strictlyDominates; -import static org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode.getLoadMethodCountersNodes; -import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes; - -import java.lang.ref.Reference; -import java.util.HashSet; -import java.util.List; - -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; -import org.graalvm.compiler.core.common.cfg.BlockMap; -import org.graalvm.compiler.core.common.type.ObjectStamp; -import org.graalvm.compiler.core.common.type.Stamp; -import org.graalvm.compiler.core.common.type.StampFactory; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.NodeMap; -import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; -import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; -import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyFixedNode; -import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode; -import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode; -import org.graalvm.compiler.nodes.AbstractBeginNode; -import org.graalvm.compiler.nodes.AbstractMergeNode; -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.FixedNode; -import org.graalvm.compiler.nodes.FixedWithNextNode; -import org.graalvm.compiler.nodes.FrameState; -import org.graalvm.compiler.nodes.LoopBeginNode; -import org.graalvm.compiler.nodes.LoopExitNode; -import org.graalvm.compiler.nodes.StateSplit; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.calc.FloatingNode; -import org.graalvm.compiler.nodes.cfg.Block; -import org.graalvm.compiler.nodes.spi.CoreProviders; -import org.graalvm.compiler.phases.BasePhase; -import org.graalvm.compiler.phases.graph.ReentrantNodeIterator; -import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; -import org.graalvm.compiler.phases.schedule.SchedulePhase; -import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; - -import jdk.vm.ci.code.BytecodeFrame; -import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; -import jdk.vm.ci.hotspot.HotSpotObjectConstant; -import jdk.vm.ci.hotspot.HotSpotResolvedJavaType; -import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.ConstantReflectionProvider; -import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaType; - -public class ReplaceConstantNodesPhase extends BasePhase { - - private final boolean verifyFingerprints; - private final boolean allowResolution; - - static Class characterCacheClass = Character.class.getDeclaredClasses()[0]; - static Class byteCacheClass = Byte.class.getDeclaredClasses()[0]; - static Class shortCacheClass = Short.class.getDeclaredClasses()[0]; - static Class integerCacheClass = Integer.class.getDeclaredClasses()[0]; - static Class longCacheClass = Long.class.getDeclaredClasses()[0]; - - static class ClassInfo { - - private ResolvedJavaType stringType; - private ResolvedJavaType referenceType; - private final HashSet builtIns = new HashSet<>(); - - ClassInfo(MetaAccessProvider metaAccessProvider) { - builtIns.add(metaAccessProvider.lookupJavaType(Boolean.class)); - - assert "java.lang.Character$CharacterCache".equals(characterCacheClass.getName()); - builtIns.add(metaAccessProvider.lookupJavaType(characterCacheClass)); - - assert "java.lang.Byte$ByteCache".equals(byteCacheClass.getName()); - builtIns.add(metaAccessProvider.lookupJavaType(byteCacheClass)); - - assert "java.lang.Short$ShortCache".equals(shortCacheClass.getName()); - builtIns.add(metaAccessProvider.lookupJavaType(shortCacheClass)); - - assert "java.lang.Integer$IntegerCache".equals(integerCacheClass.getName()); - builtIns.add(metaAccessProvider.lookupJavaType(integerCacheClass)); - - assert "java.lang.Long$LongCache".equals(longCacheClass.getName()); - builtIns.add(metaAccessProvider.lookupJavaType(longCacheClass)); - - stringType = metaAccessProvider.lookupJavaType(String.class); - referenceType = metaAccessProvider.lookupJavaType(Reference.class); - } - } - - private static boolean isReplacementNode(Node n) { - // @formatter:off - return n instanceof LoadConstantIndirectlyNode || - n instanceof LoadConstantIndirectlyFixedNode || - n instanceof ResolveDynamicConstantNode || - n instanceof ResolveConstantNode || - n instanceof InitializeKlassNode; - // @formatter:on - } - - private static boolean anyUsagesNeedReplacement(ConstantNode node) { - return node.usages().filter(n -> !isReplacementNode(n)).isNotEmpty(); - } - - private static boolean anyUsagesNeedReplacement(LoadMethodCountersNode node) { - return node.usages().filter(n -> !(n instanceof ResolveMethodAndLoadCountersNode)).isNotEmpty(); - } - - private static boolean checkForBadFingerprint(HotSpotResolvedJavaType type) { - if (type.isArray()) { - if (type.getElementalType().isPrimitive()) { - return false; - } - return ((HotSpotResolvedObjectType) (type.getElementalType())).getFingerprint() == 0; - } - return ((HotSpotResolvedObjectType) type).getFingerprint() == 0; - } - - /** - * Insert the replacement node into the graph. We may need to insert it into a place different - * than the original {@link FloatingNode} since we need to make sure that replacement will have - * a valid state assigned. - * - * @param graph - * @param stateMapper - * @param node - * @param replacement - */ - private static void insertReplacement(StructuredGraph graph, FrameStateMapperClosure stateMapper, FloatingNode node, FixedWithNextNode replacement) { - FixedWithNextNode insertionPoint = findInsertionPoint(graph, stateMapper, node); - graph.addAfterFixed(insertionPoint, replacement); - stateMapper.addState(replacement, stateMapper.getState(insertionPoint)); - } - - /** - * Find a good place to insert a stateful fixed node that is above the given node. A good - * insertion point should have a valid FrameState reaching it. - * - * @param graph - * @param stateMapper - * @param node start search from this node up - * @return an insertion point - */ - private static FixedWithNextNode findInsertionPoint(StructuredGraph graph, FrameStateMapperClosure stateMapper, FloatingNode node) { - FixedWithNextNode fixed = findFixedBeforeFloating(graph, node); - FixedWithNextNode result = findFixedWithValidState(graph, stateMapper, fixed); - return result; - } - - /** - * Find the first {@link FixedWithNextNode} that is currently scheduled before the given - * floating node. - * - * @param graph - * @param node start search from this node up - * @return the first {@link FixedWithNextNode} - */ - private static FixedWithNextNode findFixedBeforeFloating(StructuredGraph graph, FloatingNode node) { - ScheduleResult schedule = graph.getLastSchedule(); - NodeMap nodeToBlock = schedule.getNodeToBlockMap(); - Block block = nodeToBlock.get(node); - BlockMap> blockToNodes = schedule.getBlockToNodesMap(); - FixedWithNextNode result = null; - for (Node n : blockToNodes.get(block)) { - if (n.equals(node)) { - break; - } - if (n instanceof FixedWithNextNode) { - result = (FixedWithNextNode) n; - } - } - assert result != null; - return result; - } - - /** - * Find first dominating {@link FixedWithNextNode} that has a valid state reaching it starting - * from the given node. - * - * @param graph - * @param stateMapper - * @param node - * @return {@link FixedWithNextNode} that we can use as an insertion point - */ - private static FixedWithNextNode findFixedWithValidState(StructuredGraph graph, FrameStateMapperClosure stateMapper, FixedWithNextNode node) { - ScheduleResult schedule = graph.getLastSchedule(); - NodeMap nodeToBlock = schedule.getNodeToBlockMap(); - Block block = nodeToBlock.get(node); - - Node n = node; - do { - if (isFixedWithValidState(stateMapper, n)) { - return (FixedWithNextNode) n; - } - while (n != block.getBeginNode()) { - n = n.predecessor(); - if (isFixedWithValidState(stateMapper, n)) { - return (FixedWithNextNode) n; - } - } - block = block.getDominator(); - if (block != null) { - n = block.getEndNode(); - } - } while (block != null); - - return graph.start(); - } - - private static boolean isFixedWithValidState(FrameStateMapperClosure stateMapper, Node n) { - if (n instanceof FixedWithNextNode) { - FixedWithNextNode fixed = (FixedWithNextNode) n; - assert stateMapper.getState(fixed) != null; - if (!BytecodeFrame.isPlaceholderBci(stateMapper.getState(fixed).bci)) { - return true; - } - } - return false; - } - - /** - * Compute frame states for all fixed nodes in the graph. - */ - private static class FrameStateMapperClosure extends NodeIteratorClosure { - private NodeMap reachingStates; - - @Override - protected FrameState processNode(FixedNode node, FrameState previousState) { - FrameState currentState = previousState; - if (node instanceof StateSplit) { - StateSplit stateSplit = (StateSplit) node; - FrameState stateAfter = stateSplit.stateAfter(); - if (stateAfter != null) { - currentState = stateAfter; - } - } - reachingStates.put(node, currentState); - return currentState; - } - - @Override - protected FrameState merge(AbstractMergeNode merge, List states) { - FrameState singleFrameState = singleFrameState(states); - FrameState currentState = singleFrameState == null ? merge.stateAfter() : singleFrameState; - reachingStates.put(merge, currentState); - return currentState; - } - - @Override - protected FrameState afterSplit(AbstractBeginNode node, FrameState oldState) { - return oldState; - } - - @Override - protected EconomicMap processLoop(LoopBeginNode loop, FrameState initialState) { - return ReentrantNodeIterator.processLoop(this, loop, initialState).exitStates; - } - - private static FrameState singleFrameState(List states) { - FrameState singleState = states.get(0); - for (int i = 1; i < states.size(); ++i) { - if (states.get(i) != singleState) { - return null; - } - } - return singleState; - } - - FrameStateMapperClosure(StructuredGraph graph) { - reachingStates = new NodeMap<>(graph); - } - - public FrameState getState(Node n) { - return reachingStates.get(n); - } - - public void addState(Node n, FrameState s) { - reachingStates.setAndGrow(n, s); - } - } - - /** - * Try to find dominating node doing the resolution that can be reused. - * - * @param graph - * @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs - * resolution. - * @return return true if all usages of the node have been replaced - */ - private static boolean tryToReplaceWithExisting(StructuredGraph graph, ConstantNode node) { - boolean allUsagesReplaced = true; - ScheduleResult schedule = graph.getLastSchedule(); - NodeMap nodeToBlock = schedule.getNodeToBlockMap(); - BlockMap> blockToNodes = schedule.getBlockToNodesMap(); - - EconomicMap blockToExisting = EconomicMap.create(Equivalence.IDENTITY); - for (Node n : node.usages().filter(n -> isReplacementNode(n))) { - blockToExisting.put(nodeToBlock.get(n), n); - } - for (Node use : node.usages().filter(n -> !isReplacementNode(n)).snapshot()) { - boolean replaced = false; - Block b = nodeToBlock.get(use); - Node e = blockToExisting.get(b); - if (e != null) { - // There is an initialization or resolution in the same block as the use, look if - // the use is scheduled after it. - for (Node n : blockToNodes.get(b)) { - if (n.equals(use)) { - // Usage is before initialization, can't use it - break; - } - if (n.equals(e)) { - use.replaceFirstInput(node, e); - replaced = true; - break; - } - } - } - if (!replaced) { - // Look for dominating blocks that have existing nodes - for (Block d : blockToExisting.getKeys()) { - if (strictlyDominates(d, b)) { - use.replaceFirstInput(node, blockToExisting.get(d)); - replaced = true; - break; - } - } - } - if (!replaced && allUsagesReplaced) { - allUsagesReplaced = false; - } - } - return allUsagesReplaced; - } - - /** - * Replace the uses of a constant with {@link ResolveConstantNode}. - * - * @param graph - * @param stateMapper - * @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs - * resolution. - */ - private static void replaceWithResolution(StructuredGraph graph, FrameStateMapperClosure stateMapper, ConstantNode node, ClassInfo classInfo) { - HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant(); - HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType(); - - FixedWithNextNode fixedReplacement; - if (classInfo.builtIns.contains(type)) { - // Special case of klass constants that come from {@link BoxingSnippets}. - fixedReplacement = graph.add(new ResolveConstantNode(node, HotSpotConstantLoadAction.INITIALIZE)); - } else { - fixedReplacement = graph.add(new ResolveConstantNode(node)); - } - insertReplacement(graph, stateMapper, node, fixedReplacement); - node.replaceAtUsages(fixedReplacement, n -> !isReplacementNode(n)); - } - - /** - * Replace the uses of a constant with either {@link LoadConstantIndirectlyNode} if possible. - * - * @param graph - * @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs - * resolution. - * @return return true if all usages of the node have been replaced - */ - private static boolean replaceWithLoad(StructuredGraph graph, ConstantNode node, ClassInfo classInfo) { - HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant(); - HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType(); - ResolvedJavaType topMethodHolder = graph.method().getDeclaringClass(); - ValueNode replacement = null; - if ((type.isArray() && type.getComponentType().isPrimitive()) || type.equals(classInfo.referenceType)) { - // Special case for primitive arrays and j.l.ref.Reference. - // The AOT runtime pre-resolves them, so we may omit the resolution call. - replacement = graph.addOrUnique(new LoadConstantIndirectlyNode(node)); - } else if (type.equals(topMethodHolder) || (type.isAssignableFrom(topMethodHolder) && !type.isInterface())) { - // If it's a supertype of or the same class that declares the top method, we are - // guaranteed to have it resolved already. If it's an interface, we just test for - // equality. - replacement = graph.addOrUnique(new LoadConstantIndirectlyNode(node)); - } - if (replacement != null) { - node.replaceAtUsages(replacement, n -> !isReplacementNode(n)); - return true; - } - return false; - } - - /** - * Verify that {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} has a valid - * fingerprint. - * - * @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType}. - */ - private void verifyFingerprint(ConstantNode node) { - HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant(); - HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType(); - if (type != null) { - assert !metaspaceConstant.isCompressed() : "No support for replacing compressed metaspace constants"; - if (verifyFingerprints && checkForBadFingerprint(type)) { - throw new GraalError("Type with bad fingerprint: " + type); - } - } - } - - /** - * Replace {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} with indirection. - * - * @param graph - * @param stateMapper - * @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs - * resolution. - */ - private static void handleHotSpotMetaspaceConstant(StructuredGraph graph, FrameStateMapperClosure stateMapper, ConstantNode node, ClassInfo classInfo) { - HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant(); - HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType(); - if (type != null) { - if (!tryToReplaceWithExisting(graph, node) && !replaceWithLoad(graph, node, classInfo)) { - replaceWithResolution(graph, stateMapper, node, classInfo); - } - } else { - throw new GraalError("Unsupported metaspace constant type: " + type); - } - } - - /** - * Replace {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} with a load. This - * variant handles only constants that don't require resolution. - * - * @param graph - * @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs - * resolution. - */ - private static void handleHotSpotMetaspaceConstantWithoutResolution(StructuredGraph graph, ConstantNode node, ClassInfo classInfo) { - HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant(); - HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType(); - if (type != null) { - replaceWithLoad(graph, node, classInfo); - } else { - throw new GraalError("Unsupported metaspace constant type: " + type); - } - } - - /** - * Replace an object constant with an indirect load {@link ResolveConstantNode}. Currently we - * support only strings. - * - * @param graph - * @param stateMapper - * @param node {@link ConstantNode} containing a {@link HotSpotObjectConstant} that needs - * resolution. - */ - private static void handleHotSpotObjectConstant(StructuredGraph graph, FrameStateMapperClosure stateMapper, ConstantNode node, ClassInfo classInfo) { - HotSpotObjectConstant constant = (HotSpotObjectConstant) node.asJavaConstant(); - HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) constant.getType(); - if (type.equals(classInfo.stringType)) { - assert !constant.isCompressed() : "No support for replacing compressed oop constants"; - FixedWithNextNode replacement = graph.add(new ResolveConstantNode(node)); - insertReplacement(graph, stateMapper, node, replacement); - node.replaceAtUsages(replacement, n -> !(n instanceof ResolveConstantNode)); - } else { - throw new GraalError("Unsupported object constant type: " + type); - } - } - - /** - * Replace {@link LoadMethodCountersNode} with indirect load - * {@link ResolveMethodAndLoadCountersNode}, expose a klass constant of the holder. - * - * @param graph - * @param stateMapper - * @param node - * @param context - */ - private static void handleLoadMethodCounters(StructuredGraph graph, FrameStateMapperClosure stateMapper, LoadMethodCountersNode node, CoreProviders context) { - ResolvedJavaType type = node.getMethod().getDeclaringClass(); - Stamp hubStamp = context.getStampProvider().createHubStamp((ObjectStamp) StampFactory.objectNonNull()); - ConstantReflectionProvider constantReflection = context.getConstantReflection(); - ConstantNode klassHint = ConstantNode.forConstant(hubStamp, constantReflection.asObjectHub(type), context.getMetaAccess(), graph); - FixedWithNextNode replacement = graph.add(new ResolveMethodAndLoadCountersNode(node.getMethod(), klassHint)); - insertReplacement(graph, stateMapper, node, replacement); - node.replaceAtUsages(replacement, n -> !(n instanceof ResolveMethodAndLoadCountersNode)); - } - - /** - * Replace {@link LoadMethodCountersNode} with {@link ResolveMethodAndLoadCountersNode}, expose - * klass constants. - * - * @param graph - * @param stateMapper - * @param context - */ - private static void replaceLoadMethodCounters(StructuredGraph graph, FrameStateMapperClosure stateMapper, CoreProviders context) { - new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS, true).apply(graph, false); - - for (LoadMethodCountersNode node : getLoadMethodCountersNodes(graph)) { - if (anyUsagesNeedReplacement(node)) { - handleLoadMethodCounters(graph, stateMapper, node, context); - } - } - } - - /** - * Replace object and klass constants with resolution nodes or reuse preceding initializations. - * - * @param graph - * @param stateMapper - * @param classInfo - */ - private void replaceKlassesAndObjects(StructuredGraph graph, FrameStateMapperClosure stateMapper, ClassInfo classInfo) { - new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS, true).apply(graph, false); - - for (ConstantNode node : getConstantNodes(graph)) { - Constant constant = node.asConstant(); - if (constant instanceof HotSpotMetaspaceConstant && anyUsagesNeedReplacement(node)) { - verifyFingerprint(node); - handleHotSpotMetaspaceConstant(graph, stateMapper, node, classInfo); - } else if (constant instanceof HotSpotObjectConstant && anyUsagesNeedReplacement(node)) { - handleHotSpotObjectConstant(graph, stateMapper, node, classInfo); - } - } - } - - /** - * Replace well-known klass constants with indirect loads. - * - * @param graph - * @param classInfo - */ - private static void replaceKlassesWithoutResolution(StructuredGraph graph, ClassInfo classInfo) { - for (ConstantNode node : getConstantNodes(graph)) { - Constant constant = node.asConstant(); - if (constant instanceof HotSpotMetaspaceConstant && anyUsagesNeedReplacement(node)) { - handleHotSpotMetaspaceConstantWithoutResolution(graph, node, classInfo); - } - } - } - - @Override - protected void run(StructuredGraph graph, CoreProviders context) { - if (allowResolution) { - FrameStateMapperClosure stateMapper = new FrameStateMapperClosure(graph); - ReentrantNodeIterator.apply(stateMapper, graph.start(), null); - - // Replace LoadMethodCountersNode with ResolveMethodAndLoadCountersNode, expose klass - // constants. - replaceLoadMethodCounters(graph, stateMapper, context); - - // Replace object and klass constants (including the ones added in the previous pass) - // with resolution nodes. - replaceKlassesAndObjects(graph, stateMapper, new ClassInfo(context.getMetaAccess())); - } else { - replaceKlassesWithoutResolution(graph, new ClassInfo(context.getMetaAccess())); - } - } - - @Override - public boolean checkContract() { - return false; - } - - public ReplaceConstantNodesPhase(boolean allowResolution) { - this(allowResolution, true); - } - - public ReplaceConstantNodesPhase(boolean allowResolution, boolean verifyFingerprints) { - this.allowResolution = allowResolution; - this.verifyFingerprints = verifyFingerprints; - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/profiling/FinalizeProfileNodesPhase.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/profiling/FinalizeProfileNodesPhase.java deleted file mode 100644 index dd6b956439c0..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/profiling/FinalizeProfileNodesPhase.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.phases.profiling; - -import static org.graalvm.compiler.hotspot.nodes.profiling.ProfileInvokeNode.getProfileInvokeNodes; -import static org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode.getProfileNodes; - -import java.util.HashMap; -import java.util.Map; - -import org.graalvm.compiler.core.common.cfg.Loop; -import org.graalvm.compiler.hotspot.nodes.profiling.ProfileInvokeNode; -import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode; -import org.graalvm.compiler.hotspot.nodes.profiling.RandomSeedNode; -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.InvokeNode; -import org.graalvm.compiler.nodes.LoopBeginNode; -import org.graalvm.compiler.nodes.NodeView; -import org.graalvm.compiler.nodes.PhiNode; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.ValuePhiNode; -import org.graalvm.compiler.nodes.calc.AddNode; -import org.graalvm.compiler.nodes.calc.MulNode; -import org.graalvm.compiler.nodes.cfg.Block; -import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; -import org.graalvm.compiler.nodes.spi.CoreProviders; -import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.compiler.options.Option; -import org.graalvm.compiler.options.OptionKey; -import org.graalvm.compiler.options.OptionType; -import org.graalvm.compiler.phases.BasePhase; - -import jdk.vm.ci.meta.ResolvedJavaMethod; - -public class FinalizeProfileNodesPhase extends BasePhase { - private int inlineeInvokeNotificationFreqLog; - - public static class Options { - @Option(help = "Profile simple methods", type = OptionType.Expert)// - public static final OptionKey ProfileSimpleMethods = new OptionKey<>(true); - @Option(help = "Maximum number of nodes in a graph for a simple method", type = OptionType.Expert)// - public static final OptionKey SimpleMethodGraphSize = new OptionKey<>(256); - @Option(help = "Maximum number of calls in a simple method", type = OptionType.Expert)// - public static final OptionKey SimpleMethodCalls = new OptionKey<>(1); - @Option(help = "Maximum number of indirect calls in a simple moethod", type = OptionType.Expert)// - public static final OptionKey SimpleMethodIndirectCalls = new OptionKey<>(0); - - } - - public FinalizeProfileNodesPhase(int inlineeInvokeNotificationFreqLog) { - this.inlineeInvokeNotificationFreqLog = inlineeInvokeNotificationFreqLog; - } - - private static void removeAllProfilingNodes(StructuredGraph graph) { - getProfileNodes(graph).forEach((n) -> GraphUtil.removeFixedWithUnusedInputs(n)); - } - - private void assignInlineeInvokeFrequencies(StructuredGraph graph) { - for (ProfileInvokeNode node : getProfileInvokeNodes(graph)) { - ResolvedJavaMethod profiledMethod = node.getProfiledMethod(); - if (!profiledMethod.equals(graph.method())) { - // Some inlinee, reassign the inlinee frequency - node.setNotificationFreqLog(inlineeInvokeNotificationFreqLog); - } - } - } - - // Hacky heuristic to determine whether we want any profiling in this method. - // The heuristic is applied after the graph is fully formed and before the first lowering. - private static boolean simpleMethodHeuristic(StructuredGraph graph) { - if (Options.ProfileSimpleMethods.getValue(graph.getOptions())) { - return false; - } - - // Check if the graph is smallish.. - if (graph.getNodeCount() > Options.SimpleMethodGraphSize.getValue(graph.getOptions())) { - return false; - } - - // Check if method has loops - if (graph.hasLoops()) { - return false; - } - - // Check if method has calls - if (graph.getNodes().filter(InvokeNode.class).count() > Options.SimpleMethodCalls.getValue(graph.getOptions())) { - return false; - } - - // Check if method has calls that need profiling - if (graph.getNodes().filter(InvokeNode.class).filter((n) -> ((InvokeNode) n).getInvokeKind().isIndirect()).count() > Options.SimpleMethodIndirectCalls.getDefaultValue()) { - return false; - } - - return true; - } - - private static void assignRandomSources(StructuredGraph graph) { - ValueNode seed = graph.unique(new RandomSeedNode()); - ControlFlowGraph cfg = ControlFlowGraph.compute(graph, false, true, false, false); - Map loopRandomValueCache = new HashMap<>(); - - for (ProfileNode node : getProfileNodes(graph)) { - ValueNode random; - Block block = cfg.blockFor(node); - Loop loop = block.getLoop(); - // Inject LCG - // pseudo-random number generator into the loop - if (loop != null) { - LoopBeginNode loopBegin = (LoopBeginNode) loop.getHeader().getBeginNode(); - random = loopRandomValueCache.get(loopBegin); - if (random == null) { - PhiNode phi = graph.addWithoutUnique(new ValuePhiNode(seed.stamp(NodeView.DEFAULT), loopBegin)); - phi.addInput(seed); - // X_{n+1} = a*X_n + c, using glibc-like constants - ValueNode a = ConstantNode.forInt(1103515245, graph); - ValueNode c = ConstantNode.forInt(12345, graph); - ValueNode next = graph.addOrUniqueWithInputs(new AddNode(c, new MulNode(phi, a))); - for (int i = 0; i < loopBegin.getLoopEndCount(); i++) { - phi.addInput(next); - } - random = phi; - loopRandomValueCache.put(loopBegin, random); - } - } else { - // Graal doesn't compile methods with irreducible loops. So all profile nodes that - // are not in a loop are guaranteed to be executed at most once. We feed the seed - // value to such nodes directly. - random = seed; - } - node.setRandom(random); - } - } - - @Override - protected void run(StructuredGraph graph, CoreProviders context) { - if (simpleMethodHeuristic(graph)) { - removeAllProfilingNodes(graph); - return; - } - - assignInlineeInvokeFrequencies(graph); - if (ProfileNode.Options.ProbabilisticProfiling.getValue(graph.getOptions())) { - assignRandomSources(graph); - } - } - - @Override - public boolean checkContract() { - return false; - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AESCryptSubstitutions.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AESCryptSubstitutions.java deleted file mode 100644 index bca80df1a089..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AESCryptSubstitutions.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.replacements; - -import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_INTRINSIC_CONTEXT; -import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_METAACCESS; -import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_BLOCK; -import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_BLOCK_WITH_ORIGINAL_KEY; -import static org.graalvm.compiler.hotspot.HotSpotBackend.ENCRYPT_BLOCK; -import static org.graalvm.compiler.hotspot.replacements.CipherBlockChainingSubstitutions.aesCryptType; -import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.VERY_SLOW_PATH_PROBABILITY; -import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; -import static org.graalvm.compiler.replacements.ReplacementsUtil.getArrayBaseOffset; - -import org.graalvm.compiler.api.replacements.ClassSubstitution; -import org.graalvm.compiler.api.replacements.Fold; -import org.graalvm.compiler.api.replacements.MethodSubstitution; -import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; -import org.graalvm.compiler.graph.Node.ConstantNodeParameter; -import org.graalvm.compiler.graph.Node.NodeIntrinsic; -import org.graalvm.compiler.nodes.ComputeObjectAddressNode; -import org.graalvm.compiler.nodes.DeoptimizeNode; -import org.graalvm.compiler.nodes.PiNode; -import org.graalvm.compiler.nodes.extended.ForeignCallNode; -import org.graalvm.compiler.nodes.extended.RawLoadNode; -import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext; -import org.graalvm.compiler.word.Word; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.Pointer; -import org.graalvm.word.WordFactory; - -import jdk.vm.ci.meta.DeoptimizationAction; -import jdk.vm.ci.meta.DeoptimizationReason; -import jdk.vm.ci.meta.JavaKind; - -// JaCoCo Exclude - -/** - * Substitutions for {@code com.sun.crypto.provider.AESCrypt} methods. - */ -@ClassSubstitution(className = "com.sun.crypto.provider.AESCrypt", optional = true) -public class AESCryptSubstitutions { - - /** - * The AES block size is a constant 128 bits as defined by the - * standard. - */ - static final int AES_BLOCK_SIZE_IN_BYTES = 16; - - @Fold - static long kOffset(@Fold.InjectedParameter IntrinsicContext context) { - return HotSpotReplacementsUtil.getFieldOffset(aesCryptType(context), "K"); - } - - @Fold - static long lastKeyOffset(@Fold.InjectedParameter IntrinsicContext context) { - return HotSpotReplacementsUtil.getFieldOffset(aesCryptType(context), "lastKey"); - } - - @MethodSubstitution(isStatic = false) - static void encryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { - crypt(rcvr, in, inOffset, out, outOffset, true, false); - } - - @MethodSubstitution(isStatic = false) - static void implEncryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { - crypt(rcvr, in, inOffset, out, outOffset, true, false); - } - - @MethodSubstitution(isStatic = false) - static void decryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { - crypt(rcvr, in, inOffset, out, outOffset, false, false); - } - - @MethodSubstitution(isStatic = false) - static void implDecryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { - crypt(rcvr, in, inOffset, out, outOffset, false, false); - } - - private static void crypt(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset, boolean encrypt, boolean withOriginalKey) { - checkArgs(in, inOffset, out, outOffset); - Object realReceiver = PiNode.piCastNonNull(rcvr, aesCryptType(INJECTED_INTRINSIC_CONTEXT)); - Object kObject = RawLoadNode.load(realReceiver, kOffset(INJECTED_INTRINSIC_CONTEXT), JavaKind.Object, LocationIdentity.any()); - Pointer kAddr = Word.objectToTrackedPointer(kObject).add(getArrayBaseOffset(INJECTED_METAACCESS, JavaKind.Int)); - Word inAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(in, getArrayBaseOffset(INJECTED_METAACCESS, JavaKind.Byte) + inOffset)); - Word outAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(out, getArrayBaseOffset(INJECTED_METAACCESS, JavaKind.Byte) + outOffset)); - if (encrypt) { - encryptBlockStub(ENCRYPT_BLOCK, inAddr, outAddr, kAddr); - } else { - if (withOriginalKey) { - Object lastKeyObject = RawLoadNode.load(realReceiver, lastKeyOffset(INJECTED_INTRINSIC_CONTEXT), JavaKind.Object, LocationIdentity.any()); - Pointer lastKeyAddr = Word.objectToTrackedPointer(lastKeyObject).add(getArrayBaseOffset(INJECTED_METAACCESS, JavaKind.Byte)); - decryptBlockWithOriginalKeyStub(DECRYPT_BLOCK_WITH_ORIGINAL_KEY, inAddr, outAddr, kAddr, lastKeyAddr); - } else { - decryptBlockStub(DECRYPT_BLOCK, inAddr, outAddr, kAddr); - } - } - } - - /** - * Perform null and array bounds checks for arguments to a cipher operation. - */ - static void checkArgs(byte[] in, int inOffset, byte[] out, int outOffset) { - if (probability(VERY_SLOW_PATH_PROBABILITY, inOffset < 0 || in.length - AES_BLOCK_SIZE_IN_BYTES < inOffset || outOffset < 0 || out.length - AES_BLOCK_SIZE_IN_BYTES < outOffset)) { - DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); - } - } - - @NodeIntrinsic(ForeignCallNode.class) - public static native void encryptBlockStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key); - - @NodeIntrinsic(ForeignCallNode.class) - public static native void decryptBlockStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key); - - @NodeIntrinsic(ForeignCallNode.class) - public static native void decryptBlockWithOriginalKeyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key, Pointer originalKey); -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CallSiteTargetNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CallSiteTargetNode.java index 51eab2f950e9..774c74f2ea86 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CallSiteTargetNode.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CallSiteTargetNode.java @@ -34,7 +34,7 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.compiler.replacements.nodes.MacroStateSplitNode; +import org.graalvm.compiler.replacements.nodes.MacroNode; import jdk.vm.ci.hotspot.HotSpotObjectConstant; import jdk.vm.ci.meta.Assumptions; @@ -42,7 +42,7 @@ import jdk.vm.ci.meta.MetaAccessProvider; @NodeInfo -public final class CallSiteTargetNode extends MacroStateSplitNode implements Canonicalizable, Lowerable { +public final class CallSiteTargetNode extends MacroNode implements Canonicalizable, Lowerable { public static final NodeClass TYPE = NodeClass.create(CallSiteTargetNode.class); diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CipherBlockChainingSubstitutions.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CipherBlockChainingSubstitutions.java deleted file mode 100644 index 643a2203f09b..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CipherBlockChainingSubstitutions.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.replacements; - -import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_INTRINSIC_CONTEXT; -import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_METAACCESS; -import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT; -import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_WITH_ORIGINAL_KEY; -import static org.graalvm.compiler.hotspot.HotSpotBackend.ENCRYPT; -import static org.graalvm.compiler.nodes.PiNode.piCastNonNull; -import static org.graalvm.compiler.nodes.java.InstanceOfNode.doInstanceof; - -import org.graalvm.compiler.api.replacements.ClassSubstitution; -import org.graalvm.compiler.api.replacements.Fold; -import org.graalvm.compiler.api.replacements.MethodSubstitution; -import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; -import org.graalvm.compiler.graph.Node.ConstantNodeParameter; -import org.graalvm.compiler.graph.Node.NodeIntrinsic; -import org.graalvm.compiler.nodes.ComputeObjectAddressNode; -import org.graalvm.compiler.nodes.extended.ForeignCallNode; -import org.graalvm.compiler.nodes.extended.RawLoadNode; -import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext; -import org.graalvm.compiler.replacements.ReplacementsUtil; -import org.graalvm.compiler.word.Word; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.Pointer; -import org.graalvm.word.WordFactory; - -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaType; - -// JaCoCo Exclude - -/** - * Substitutions for {@code com.sun.crypto.provider.CipherBlockChaining} methods. - */ -@ClassSubstitution(className = "com.sun.crypto.provider.CipherBlockChaining", optional = true) -public class CipherBlockChainingSubstitutions { - - @Fold - static ResolvedJavaType aesCryptType(@Fold.InjectedParameter IntrinsicContext context) { - return HotSpotReplacementsUtil.getType(context, "Lcom/sun/crypto/provider/AESCrypt;"); - } - - @MethodSubstitution(isStatic = false) - static int encrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { - Object realReceiver = piCastNonNull(rcvr, HotSpotReplacementsUtil.methodHolderClass(INJECTED_INTRINSIC_CONTEXT)); - Object embeddedCipher = RawLoadNode.load(realReceiver, embeddedCipherOffset(INJECTED_INTRINSIC_CONTEXT), JavaKind.Object, LocationIdentity.any()); - if (doInstanceof(aesCryptType(INJECTED_INTRINSIC_CONTEXT), embeddedCipher)) { - Object aesCipher = piCastNonNull(embeddedCipher, aesCryptType(INJECTED_INTRINSIC_CONTEXT)); - crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true, false); - return inLength; - } else { - return encrypt(realReceiver, in, inOffset, inLength, out, outOffset); - } - } - - @Fold - static long embeddedCipherOffset(@Fold.InjectedParameter IntrinsicContext context) { - return HotSpotReplacementsUtil.getFieldOffset(HotSpotReplacementsUtil.getType(context, "Lcom/sun/crypto/provider/FeedbackCipher;"), "embeddedCipher"); - } - - @Fold - static long rOffset(@Fold.InjectedParameter IntrinsicContext intrinsicContext) { - return HotSpotReplacementsUtil.getFieldOffset(HotSpotReplacementsUtil.methodHolderClass(intrinsicContext), "r"); - } - - @MethodSubstitution(isStatic = false, value = "implEncrypt") - static int implEncrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { - Object realReceiver = piCastNonNull(rcvr, HotSpotReplacementsUtil.methodHolderClass(INJECTED_INTRINSIC_CONTEXT)); - Object embeddedCipher = RawLoadNode.load(realReceiver, embeddedCipherOffset(INJECTED_INTRINSIC_CONTEXT), JavaKind.Object, LocationIdentity.any()); - if (doInstanceof(aesCryptType(INJECTED_INTRINSIC_CONTEXT), embeddedCipher)) { - Object aesCipher = piCastNonNull(embeddedCipher, aesCryptType(INJECTED_INTRINSIC_CONTEXT)); - crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true, false); - return inLength; - } else { - return implEncrypt(realReceiver, in, inOffset, inLength, out, outOffset); - } - } - - @MethodSubstitution(isStatic = false) - static int decrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { - Object realReceiver = piCastNonNull(rcvr, HotSpotReplacementsUtil.methodHolderClass(INJECTED_INTRINSIC_CONTEXT)); - Object embeddedCipher = RawLoadNode.load(realReceiver, embeddedCipherOffset(INJECTED_INTRINSIC_CONTEXT), JavaKind.Object, LocationIdentity.any()); - if (in != out && doInstanceof(aesCryptType(INJECTED_INTRINSIC_CONTEXT), embeddedCipher)) { - Object aesCipher = piCastNonNull(embeddedCipher, aesCryptType(INJECTED_INTRINSIC_CONTEXT)); - crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, false); - return inLength; - } else { - return decrypt(realReceiver, in, inOffset, inLength, out, outOffset); - } - } - - @MethodSubstitution(isStatic = false) - static int implDecrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { - Object realReceiver = piCastNonNull(rcvr, HotSpotReplacementsUtil.methodHolderClass(INJECTED_INTRINSIC_CONTEXT)); - Object embeddedCipher = RawLoadNode.load(realReceiver, embeddedCipherOffset(INJECTED_INTRINSIC_CONTEXT), JavaKind.Object, LocationIdentity.any()); - if (in != out && doInstanceof(aesCryptType(INJECTED_INTRINSIC_CONTEXT), embeddedCipher)) { - Object aesCipher = piCastNonNull(embeddedCipher, aesCryptType(INJECTED_INTRINSIC_CONTEXT)); - crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, false); - return inLength; - } else { - return implDecrypt(realReceiver, in, inOffset, inLength, out, outOffset); - } - } - - private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt, boolean withOriginalKey) { - AESCryptSubstitutions.checkArgs(in, inOffset, out, outOffset); - Object realReceiver = piCastNonNull(rcvr, HotSpotReplacementsUtil.methodHolderClass(INJECTED_INTRINSIC_CONTEXT)); - Object aesCipher = piCastNonNull(embeddedCipher, aesCryptType(INJECTED_INTRINSIC_CONTEXT)); - Object kObject = RawLoadNode.load(aesCipher, AESCryptSubstitutions.kOffset(INJECTED_INTRINSIC_CONTEXT), JavaKind.Object, LocationIdentity.any()); - Object rObject = RawLoadNode.load(realReceiver, rOffset(INJECTED_INTRINSIC_CONTEXT), JavaKind.Object, LocationIdentity.any()); - Pointer kAddr = Word.objectToTrackedPointer(kObject).add(ReplacementsUtil.getArrayBaseOffset(INJECTED_METAACCESS, JavaKind.Int)); - Pointer rAddr = Word.objectToTrackedPointer(rObject).add(ReplacementsUtil.getArrayBaseOffset(INJECTED_METAACCESS, JavaKind.Byte)); - Word inAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(in, ReplacementsUtil.getArrayBaseOffset(INJECTED_METAACCESS, JavaKind.Byte) + inOffset)); - Word outAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(out, ReplacementsUtil.getArrayBaseOffset(INJECTED_METAACCESS, JavaKind.Byte) + outOffset)); - if (encrypt) { - encryptAESCryptStub(ENCRYPT, inAddr, outAddr, kAddr, rAddr, inLength); - } else { - if (withOriginalKey) { - Object lastKeyObject = RawLoadNode.load(aesCipher, AESCryptSubstitutions.lastKeyOffset(INJECTED_INTRINSIC_CONTEXT), JavaKind.Object, LocationIdentity.any()); - Pointer lastKeyAddr = Word.objectToTrackedPointer(lastKeyObject).add(ReplacementsUtil.getArrayBaseOffset(INJECTED_METAACCESS, JavaKind.Byte)); - decryptAESCryptWithOriginalKeyStub(DECRYPT_WITH_ORIGINAL_KEY, inAddr, outAddr, kAddr, rAddr, inLength, lastKeyAddr); - } else { - decryptAESCryptStub(DECRYPT, inAddr, outAddr, kAddr, rAddr, inLength); - } - } - } - - @NodeIntrinsic(ForeignCallNode.class) - public static native void encryptAESCryptStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key, Pointer r, int inLength); - - @NodeIntrinsic(ForeignCallNode.class) - public static native void decryptAESCryptStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key, Pointer r, int inLength); - - @NodeIntrinsic(ForeignCallNode.class) - public static native void decryptAESCryptWithOriginalKeyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key, Pointer r, int inLength, Pointer originalKey); -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java index 61a1e808dbf9..3d05e7d1701a 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java @@ -32,8 +32,6 @@ import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.Node.NodeIntrinsicFactory; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.Canonicalizable; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; import org.graalvm.compiler.hotspot.word.KlassPointer; import org.graalvm.compiler.nodeinfo.NodeInfo; @@ -49,6 +47,8 @@ import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; import org.graalvm.compiler.nodes.memory.ReadNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.nodes.spi.Canonicalizable; +import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.word.LocationIdentity; @@ -128,8 +128,12 @@ public Node canonical(CanonicalizerTool tool) { @NodeIntrinsic public static native KlassPointer readClass(Class clazzNonNull); + public static KlassPointer piCastNonNull(KlassPointer object, GuardingNode anchor) { + return intrinsifiedPiNode(object, anchor, PiNode.IntrinsifyOp.NON_NULL); + } + @NodeIntrinsic(PiNode.class) - public static native KlassPointer piCastNonNull(Object object, GuardingNode anchor); + private static native KlassPointer intrinsifiedPiNode(KlassPointer object, GuardingNode anchor, @ConstantNodeParameter PiNode.IntrinsifyOp intrinsifyOp); @Override public ValueNode getValue() { diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CounterModeSubstitutions.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CounterModeSubstitutions.java deleted file mode 100644 index ae631adb2b53..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CounterModeSubstitutions.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.replacements; - -import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_INTRINSIC_CONTEXT; -import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_METAACCESS; -import static org.graalvm.compiler.hotspot.replacements.CipherBlockChainingSubstitutions.aesCryptType; -import static org.graalvm.compiler.hotspot.replacements.CipherBlockChainingSubstitutions.embeddedCipherOffset; -import static org.graalvm.compiler.nodes.PiNode.piCastNonNull; -import static org.graalvm.compiler.nodes.java.InstanceOfNode.doInstanceof; - -import org.graalvm.compiler.api.replacements.ClassSubstitution; -import org.graalvm.compiler.api.replacements.Fold; -import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; -import org.graalvm.compiler.api.replacements.MethodSubstitution; -import org.graalvm.compiler.hotspot.HotSpotBackend; -import org.graalvm.compiler.nodes.ComputeObjectAddressNode; -import org.graalvm.compiler.nodes.extended.RawLoadNode; -import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext; -import org.graalvm.compiler.replacements.ReplacementsUtil; -import org.graalvm.compiler.word.Word; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.WordFactory; - -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaType; - -@ClassSubstitution(className = "com.sun.crypto.provider.CounterMode", optional = true) -public class CounterModeSubstitutions { - - @MethodSubstitution(isStatic = false) - static int implCrypt(Object receiver, byte[] in, int inOff, int len, byte[] out, int outOff) { - Object realReceiver = piCastNonNull(receiver, HotSpotReplacementsUtil.methodHolderClass(INJECTED_INTRINSIC_CONTEXT)); - Object embeddedCipher = RawLoadNode.load(realReceiver, embeddedCipherOffset(INJECTED_INTRINSIC_CONTEXT), JavaKind.Object, LocationIdentity.any()); - if (doInstanceof(aesCryptType(INJECTED_INTRINSIC_CONTEXT), embeddedCipher)) { - Object aesCipher = piCastNonNull(embeddedCipher, aesCryptType(INJECTED_INTRINSIC_CONTEXT)); - - Word srcAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(in, ReplacementsUtil.getArrayBaseOffset(INJECTED_METAACCESS, JavaKind.Byte) + inOff)); - Word dstAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(out, ReplacementsUtil.getArrayBaseOffset(INJECTED_METAACCESS, JavaKind.Byte) + outOff)); - Word usedPtr = WordFactory.unsigned(ComputeObjectAddressNode.get(realReceiver, usedOffset(INJECTED_INTRINSIC_CONTEXT))); - - int cntOffset = counterOffset(INJECTED_INTRINSIC_CONTEXT); - int encCntOffset = encCounterOffset(INJECTED_INTRINSIC_CONTEXT); - Object kObject = RawLoadNode.load(aesCipher, AESCryptSubstitutions.kOffset(INJECTED_INTRINSIC_CONTEXT), JavaKind.Object, LocationIdentity.any()); - Object cntObj = RawLoadNode.load(realReceiver, cntOffset, JavaKind.Object, LocationIdentity.any()); - Object encCntObj = RawLoadNode.load(realReceiver, encCntOffset, JavaKind.Object, LocationIdentity.any()); - - Word kPtr = Word.objectToTrackedPointer(kObject).add(ReplacementsUtil.getArrayBaseOffset(INJECTED_METAACCESS, JavaKind.Int)); - Word cntPtr = Word.objectToTrackedPointer(cntObj).add(ReplacementsUtil.getArrayBaseOffset(INJECTED_METAACCESS, JavaKind.Byte)); - Word encCntPtr = Word.objectToTrackedPointer(encCntObj).add(ReplacementsUtil.getArrayBaseOffset(INJECTED_METAACCESS, JavaKind.Byte)); - - return HotSpotBackend.counterModeAESCrypt(srcAddr, dstAddr, kPtr, cntPtr, len, encCntPtr, usedPtr); - } else { - return implCrypt(realReceiver, in, inOff, len, out, outOff); - } - } - - static ResolvedJavaType counterModeType(IntrinsicContext context) { - return HotSpotReplacementsUtil.getType(context, "Lcom/sun/crypto/provider/CounterMode;"); - } - - @Fold - static int counterOffset(@InjectedParameter IntrinsicContext context) { - return HotSpotReplacementsUtil.getFieldOffset(counterModeType(context), "counter"); - } - - @Fold - static int encCounterOffset(@InjectedParameter IntrinsicContext context) { - return HotSpotReplacementsUtil.getFieldOffset(counterModeType(context), "encryptedCounter"); - } - - @Fold - static int usedOffset(@InjectedParameter IntrinsicContext context) { - return HotSpotReplacementsUtil.getFieldOffset(counterModeType(context), "used"); - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/FastNotifyNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/FastNotifyNode.java index ac223e1a0fe1..f3d899f231b7 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/FastNotifyNode.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/FastNotifyNode.java @@ -81,7 +81,7 @@ public void setStateDuring(FrameState stateDuring) { @Override public void computeStateDuring(FrameState currentStateAfter) { - FrameState newStateDuring = currentStateAfter.duplicateModifiedDuringCall(bci, asNode().getStackKind()); + FrameState newStateDuring = currentStateAfter.duplicateModifiedDuringCall(bci, getStackKind()); setStateDuring(newStateDuring); } diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotAllocationSnippets.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotAllocationSnippets.java index 1a54e1751168..c57b9dff5f95 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotAllocationSnippets.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotAllocationSnippets.java @@ -27,7 +27,6 @@ import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateRecompile; import static jdk.vm.ci.meta.DeoptimizationAction.None; import static jdk.vm.ci.meta.DeoptimizationReason.RuntimeConstraint; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.core.common.GraalOptions.MinimalBulkZeroingSize; import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_OPTIONVALUES; import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; @@ -91,8 +90,6 @@ import org.graalvm.compiler.hotspot.meta.HotSpotProviders; import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; import org.graalvm.compiler.hotspot.nodes.KlassBeingInitializedCheckNode; -import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyFixedNode; -import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode; import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; import org.graalvm.compiler.hotspot.word.KlassPointer; import org.graalvm.compiler.nodes.ConstantNode; @@ -151,7 +148,7 @@ public HotSpotAllocationSnippets(GraalHotSpotVMConfig config, HotSpotRegistersPr protected Object allocateInstance(KlassPointer hub, Word prototypeMarkWord, @ConstantParameter long size, - @ConstantParameter boolean fillContents, + @ConstantParameter FillContent fillContents, @ConstantParameter boolean emitMemoryBarrier, @ConstantParameter HotSpotAllocationProfilingData profilingData) { Object result = allocateInstanceImpl(hub.asWord(), prototypeMarkWord, WordFactory.unsigned(size), fillContents, emitMemoryBarrier, true, profilingData); @@ -164,7 +161,7 @@ public Object allocateArray(KlassPointer hub, int length, @ConstantParameter int arrayBaseOffset, @ConstantParameter int log2ElementSize, - @ConstantParameter boolean fillContents, + @ConstantParameter FillContent fillContents, @ConstantParameter int fillStartOffset, @ConstantParameter boolean emitMemoryBarrier, @ConstantParameter boolean maybeUnroll, @@ -176,24 +173,9 @@ public Object allocateArray(KlassPointer hub, return piArrayCastToSnippetReplaceeStamp(result, length); } - @Snippet - protected Object allocateInstancePIC(KlassPointer hub, - Word prototypeMarkWord, - @ConstantParameter long size, - @ConstantParameter boolean fillContents, - @ConstantParameter boolean emitMemoryBarrier, - @ConstantParameter HotSpotAllocationProfilingData profilingData) { - // Klass must be initialized by the time the first instance is allocated, therefore we can - // just load it from the corresponding cell and avoid the resolution check. We have to use a - // fixed load though, to prevent it from floating above the initialization. - KlassPointer picHub = LoadConstantIndirectlyFixedNode.loadKlass(hub); - Object result = allocateInstanceImpl(picHub.asWord(), prototypeMarkWord, WordFactory.unsigned(size), fillContents, emitMemoryBarrier, true, profilingData); - return piCastToSnippetReplaceeStamp(result); - } - @Snippet public Object allocateInstanceDynamic(@NonNullParameter Class type, - @ConstantParameter boolean fillContents, + @ConstantParameter FillContent fillContents, @ConstantParameter boolean emitMemoryBarrier, @ConstantParameter HotSpotAllocationProfilingData profilingData) { @@ -238,50 +220,12 @@ private static Class validateNewInstanceClass(Class type, Class classCl return nonNullType; } - @Snippet - public Object allocatePrimitiveArrayPIC(KlassPointer hub, - Word prototypeMarkWord, - int length, - @ConstantParameter int arrayBaseOffset, - @ConstantParameter int log2ElementSize, - @ConstantParameter boolean fillContents, - @ConstantParameter int fillStartOffset, - @ConstantParameter boolean emitMemoryBarrier, - @ConstantParameter boolean maybeUnroll, - @ConstantParameter boolean supportsBulkZeroing, - @ConstantParameter boolean supportsOptimizedFilling, - @ConstantParameter HotSpotAllocationProfilingData profilingData) { - // Primitive array types are eagerly pre-resolved. We can use a floating load. - KlassPointer picHub = LoadConstantIndirectlyNode.loadKlass(hub); - return allocateArrayImpl(picHub.asWord(), prototypeMarkWord, length, arrayBaseOffset, log2ElementSize, fillContents, fillStartOffset, emitMemoryBarrier, maybeUnroll, supportsBulkZeroing, - supportsOptimizedFilling, profilingData); - } - - @Snippet - public Object allocateArrayPIC(KlassPointer hub, - Word prototypeMarkWord, - int length, - @ConstantParameter int arrayBaseOffset, - @ConstantParameter int log2ElementSize, - @ConstantParameter boolean fillContents, - @ConstantParameter int fillStartOffset, - @ConstantParameter boolean emitMemoryBarrier, - @ConstantParameter boolean maybeUnroll, - @ConstantParameter boolean supportsBulkZeroing, - @ConstantParameter boolean supportsOptimizedFilling, - @ConstantParameter HotSpotAllocationProfilingData profilingData) { - // Array type would be resolved by dominating resolution. - KlassPointer picHub = LoadConstantIndirectlyFixedNode.loadKlass(hub); - return allocateArrayImpl(picHub.asWord(), prototypeMarkWord, length, arrayBaseOffset, log2ElementSize, fillContents, fillStartOffset, emitMemoryBarrier, maybeUnroll, supportsBulkZeroing, - supportsOptimizedFilling, profilingData); - } - @Snippet public Object allocateArrayDynamic(Class elementType, Word prototypeMarkWord, Class voidClass, int length, - @ConstantParameter boolean fillContents, + @ConstantParameter FillContent fillContents, @ConstantParameter boolean emitMemoryBarrier, @ConstantParameter JavaKind knownElementKind, @ConstantParameter int knownLayoutHelper, @@ -338,13 +282,6 @@ protected Object newmultiarray(KlassPointer hub, @ConstantParameter int rank, @V return newMultiArrayImpl(hub.asWord(), rank, dimensions); } - @Snippet - private Object newmultiarrayPIC(KlassPointer hub, @ConstantParameter int rank, @VarargsParameter int[] dimensions) { - // Array type would be resolved by dominating resolution. - KlassPointer picHub = LoadConstantIndirectlyFixedNode.loadKlass(hub); - return newMultiArrayImpl(picHub.asWord(), rank, dimensions); - } - @Snippet private void verifyHeap() { Word tlabInfo = getTLABInfo(); @@ -614,15 +551,11 @@ public static class Templates extends AbstractTemplates { private HotSpotAllocationProfilingData profilingData; private final SnippetInfo allocateInstance; - private final SnippetInfo allocateInstancePIC; private final SnippetInfo allocateArray; - private final SnippetInfo allocateArrayPIC; - private final SnippetInfo allocatePrimitiveArrayPIC; private final SnippetInfo allocateArrayDynamic; private final SnippetInfo allocateInstanceDynamic; private final SnippetInfo validateNewInstanceClass; private final SnippetInfo newmultiarray; - private final SnippetInfo newmultiarrayPIC; private final SnippetInfo verifyHeap; private final SnippetInfo threadBeingInitializedCheck; @@ -636,11 +569,6 @@ public Templates(HotSpotAllocationSnippets receiver, OptionValues options, Itera allocateInstance = snippet(HotSpotAllocationSnippets.class, "allocateInstance", null, receiver, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION, PROTOTYPE_MARK_WORD_LOCATION); allocateArray = snippet(HotSpotAllocationSnippets.class, "allocateArray", null, receiver, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION); - allocateInstancePIC = snippet(HotSpotAllocationSnippets.class, "allocateInstancePIC", null, receiver, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION, - PROTOTYPE_MARK_WORD_LOCATION); - allocateArrayPIC = snippet(HotSpotAllocationSnippets.class, "allocateArrayPIC", null, receiver, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION); - allocatePrimitiveArrayPIC = snippet(HotSpotAllocationSnippets.class, "allocatePrimitiveArrayPIC", null, receiver, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, - TLAB_END_LOCATION); allocateArrayDynamic = snippet(HotSpotAllocationSnippets.class, "allocateArrayDynamic", null, receiver, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION); allocateInstanceDynamic = snippet(HotSpotAllocationSnippets.class, "allocateInstanceDynamic", null, receiver, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, @@ -648,7 +576,6 @@ public Templates(HotSpotAllocationSnippets receiver, OptionValues options, Itera validateNewInstanceClass = snippet(HotSpotAllocationSnippets.class, "validateNewInstanceClass", MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION, PROTOTYPE_MARK_WORD_LOCATION, CLASS_INIT_STATE_LOCATION); newmultiarray = snippet(HotSpotAllocationSnippets.class, "newmultiarray", null, receiver, TLAB_TOP_LOCATION, TLAB_END_LOCATION); - newmultiarrayPIC = snippet(HotSpotAllocationSnippets.class, "newmultiarrayPIC", null, receiver, TLAB_TOP_LOCATION, TLAB_END_LOCATION); verifyHeap = snippet(HotSpotAllocationSnippets.class, "verifyHeap", null, receiver); threadBeingInitializedCheck = snippet(HotSpotAllocationSnippets.class, "threadBeingInitializedCheck", null, receiver); } @@ -677,12 +604,11 @@ public void lower(NewInstanceNode node, LoweringTool tool) { long size = instanceSize(type); OptionValues localOptions = graph.getOptions(); - SnippetInfo snippet = GeneratePIC.getValue(localOptions) ? allocateInstancePIC : allocateInstance; - Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); + Arguments args = new Arguments(allocateInstance, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hub); args.add("prototypeMarkWord", type.prototypeMarkWord()); args.addConst("size", size); - args.addConst("fillContents", node.fillContents()); + args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("profilingData", getProfilingData(localOptions, "instance", type)); @@ -704,18 +630,7 @@ public void lower(NewArrayNode node, LoweringTool tool) { int log2ElementSize = CodeUtil.log2(tool.getMetaAccess().getArrayIndexScale(elementKind)); OptionValues localOptions = graph.getOptions(); - SnippetInfo snippet; - if (GeneratePIC.getValue(localOptions)) { - if (elementType.isPrimitive()) { - snippet = allocatePrimitiveArrayPIC; - } else { - snippet = allocateArrayPIC; - } - } else { - snippet = allocateArray; - } - - Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); + Arguments args = new Arguments(allocateArray, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hub); assert arrayType.prototypeMarkWord() == lookupArrayClass(tool, JavaKind.Object).prototypeMarkWord() : "all array types are assumed to have the same prototypeMarkWord"; args.add("prototypeMarkWord", arrayType.prototypeMarkWord()); @@ -723,7 +638,7 @@ public void lower(NewArrayNode node, LoweringTool tool) { args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length)); args.addConst("arrayBaseOffset", arrayBaseOffset); args.addConst("log2ElementSize", log2ElementSize); - args.addConst("fillContents", node.fillContents()); + args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); args.addConst("fillStartOffset", arrayBaseOffset); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("maybeUnroll", length.isConstant()); @@ -738,7 +653,6 @@ public void lower(NewArrayNode node, LoweringTool tool) { public void lower(NewMultiArrayNode node, LoweringTool tool) { StructuredGraph graph = node.graph(); - OptionValues localOptions = graph.getOptions(); int rank = node.dimensionCount(); ValueNode[] dims = new ValueNode[rank]; for (int i = 0; i < node.dimensionCount(); i++) { @@ -747,8 +661,7 @@ public void lower(NewMultiArrayNode node, LoweringTool tool) { HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) node.type(); ConstantNode hub = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), type.klass(), providers.getMetaAccess(), graph); - SnippetInfo snippet = GeneratePIC.getValue(localOptions) ? newmultiarrayPIC : newmultiarray; - Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); + Arguments args = new Arguments(newmultiarray, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hub); args.addConst("rank", rank); args.addVarargs("dimensions", int.class, StampFactory.forKind(JavaKind.Int), dims); @@ -761,7 +674,7 @@ public void lower(DynamicNewInstanceNode node, LoweringTool tool) { Arguments args = new Arguments(allocateInstanceDynamic, node.graph().getGuardsStage(), tool.getLoweringStage()); args.add("type", node.getInstanceType()); - args.addConst("fillContents", node.fillContents()); + args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("profilingData", getProfilingData(localOptions, "", null)); @@ -789,7 +702,7 @@ public void lower(DynamicNewArrayNode node, LoweringTool tool) { args.add("prototypeMarkWord", lookupArrayClass(tool, JavaKind.Object).prototypeMarkWord()); args.add("voidClass", voidClass); args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length)); - args.addConst("fillContents", node.fillContents()); + args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); /* * We use Kind.Illegal as a marker value instead of null because constant snippet diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotArraySubstitutions.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotArraySubstitutions.java deleted file mode 100644 index c2b6dc9fae03..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotArraySubstitutions.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.replacements; - -import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_ARRAY_KLASS_LOCATION; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayKlassOffset; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadKlassFromObject; - -import java.lang.reflect.Array; - -import org.graalvm.compiler.api.directives.GraalDirectives; -import org.graalvm.compiler.api.replacements.ClassSubstitution; -import org.graalvm.compiler.api.replacements.MethodSubstitution; -import org.graalvm.compiler.nodes.java.DynamicNewArrayNode; - -// JaCoCo Exclude - -/** - * Substitutions for {@link Array} methods. - */ -@ClassSubstitution(Array.class) -public class HotSpotArraySubstitutions { - - @MethodSubstitution - public static Object newInstance(Class componentType, int length) { - if (componentType == null || loadKlassFromObject(componentType, arrayKlassOffset(INJECTED_VMCONFIG), CLASS_ARRAY_KLASS_LOCATION).isNull()) { - // Exit the intrinsic here for the case where the array class does not exist - return newInstance(componentType, length); - } - return DynamicNewArrayNode.newArray(GraalDirectives.guardingNonNull(componentType), length); - } - -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotClassSubstitutions.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotClassSubstitutions.java deleted file mode 100644 index 7dac09eda4de..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotClassSubstitutions.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.replacements; - -import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_METAACCESS; -import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.ARRAY_KLASS_COMPONENT_MIRROR; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_ACCESS_FLAGS_LOCATION; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_MODIFIER_FLAGS_LOCATION; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_SUPER_KLASS_LOCATION; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayKlassComponentMirrorOffset; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.jvmAccIsHiddenClass; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.klassAccessFlagsOffset; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.klassIsArray; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.klassModifierFlagsOffset; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.klassSuperKlassOffset; - -import java.lang.reflect.Modifier; - -import org.graalvm.compiler.api.replacements.ClassSubstitution; -import org.graalvm.compiler.api.replacements.Fold; -import org.graalvm.compiler.api.replacements.MethodSubstitution; -import org.graalvm.compiler.hotspot.word.KlassPointer; -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.PiNode; -import org.graalvm.compiler.nodes.SnippetAnchorNode; - -import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaType; - -// JaCoCo Exclude - -/** - * Substitutions for {@link java.lang.Class} methods. - */ -@ClassSubstitution(Class.class) -public class HotSpotClassSubstitutions { - - @MethodSubstitution(isStatic = false) - public static int getModifiers(final Class thisObj) { - KlassPointer klass = ClassGetHubNode.readClass(thisObj); - if (klass.isNull()) { - // Class for primitive type - return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC; - } else { - return klass.readInt(klassModifierFlagsOffset(INJECTED_VMCONFIG), KLASS_MODIFIER_FLAGS_LOCATION); - } - } - - @MethodSubstitution(isStatic = false) - public static boolean isInterface(final Class thisObj) { - KlassPointer klass = ClassGetHubNode.readClass(thisObj); - if (klass.isNull()) { - // Class for primitive type - return false; - } else { - int accessFlags = klass.readInt(klassAccessFlagsOffset(INJECTED_VMCONFIG), KLASS_ACCESS_FLAGS_LOCATION); - return (accessFlags & Modifier.INTERFACE) != 0; - } - } - - @MethodSubstitution(isStatic = false, optional = true) - public static boolean isHidden(final Class thisObj) { - KlassPointer klass = ClassGetHubNode.readClass(thisObj); - if (klass.isNull()) { - // Class for primitive type - return false; - } else { - int accessFlags = klass.readInt(klassAccessFlagsOffset(INJECTED_VMCONFIG), KLASS_ACCESS_FLAGS_LOCATION); - return (accessFlags & (jvmAccIsHiddenClass(INJECTED_VMCONFIG))) != 0; - } - } - - @Fold - public static ResolvedJavaType getObjectType(@Fold.InjectedParameter MetaAccessProvider metaAccesss) { - return metaAccesss.lookupJavaType(Object.class); - } - - @MethodSubstitution(isStatic = false) - public static Class getSuperclass(final Class thisObj) { - KlassPointer klass = ClassGetHubNode.readClass(thisObj); - if (!klass.isNull()) { - KlassPointer klassNonNull = ClassGetHubNode.piCastNonNull(klass, SnippetAnchorNode.anchor()); - int accessFlags = klassNonNull.readInt(klassAccessFlagsOffset(INJECTED_VMCONFIG), KLASS_ACCESS_FLAGS_LOCATION); - if ((accessFlags & Modifier.INTERFACE) == 0) { - if (klassIsArray(klassNonNull)) { - return ConstantNode.forClass(getObjectType(INJECTED_METAACCESS)); - } else { - KlassPointer superKlass = klassNonNull.readKlassPointer(klassSuperKlassOffset(INJECTED_VMCONFIG), KLASS_SUPER_KLASS_LOCATION); - if (superKlass.isNull()) { - return null; - } else { - KlassPointer superKlassNonNull = ClassGetHubNode.piCastNonNull(superKlass, SnippetAnchorNode.anchor()); - return HubGetClassNode.readClass(superKlassNonNull); - } - } - } - } else { - // Class for primitive type - } - return null; - } - - @MethodSubstitution(isStatic = false) - public static Class getComponentType(final Class thisObj) { - KlassPointer klass = ClassGetHubNode.readClass(thisObj); - if (!klass.isNull()) { - KlassPointer klassNonNull = ClassGetHubNode.piCastNonNull(klass, SnippetAnchorNode.anchor()); - if (klassIsArray(klassNonNull)) { - return PiNode.asNonNullClass(klassNonNull.readObject(arrayKlassComponentMirrorOffset(INJECTED_VMCONFIG), ARRAY_KLASS_COMPONENT_MIRROR)); - } - } else { - // Class for primitive type - } - return null; - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotG1WriteBarrierSnippets.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotG1WriteBarrierSnippets.java index a1e4e7ff0fa2..18fe93b4f2d6 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotG1WriteBarrierSnippets.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotG1WriteBarrierSnippets.java @@ -38,7 +38,6 @@ import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; -import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode; import org.graalvm.compiler.hotspot.nodes.HotSpotCompressionNode; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.gc.G1ArrayRangePostWriteBarrier; @@ -93,8 +92,8 @@ protected int objectArrayIndexScale() { } @Override - protected int satbQueueMarkingOffset() { - return HotSpotReplacementsUtil.g1SATBQueueMarkingOffset(INJECTED_VMCONFIG); + protected int satbQueueMarkingActiveOffset() { + return HotSpotReplacementsUtil.g1SATBQueueMarkingActiveOffset(INJECTED_VMCONFIG); } @Override @@ -129,14 +128,14 @@ protected byte youngCardValue() { @Override protected Word cardTableAddress(Pointer oop) { - Word cardTable = WordFactory.unsigned(GraalHotSpotVMConfigNode.cardTableAddress()); + Word cardTable = WordFactory.unsigned(HotSpotReplacementsUtil.cardTableStart(INJECTED_VMCONFIG)); int cardTableShift = HotSpotReplacementsUtil.cardTableShift(INJECTED_VMCONFIG); return cardTable.add(oop.unsignedShiftRight(cardTableShift)); } @Override protected int logOfHeapRegionGrainBytes() { - return GraalHotSpotVMConfigNode.logOfHeapRegionGrainBytes(); + return HotSpotReplacementsUtil.logOfHeapRegionGrainBytes(INJECTED_VMCONFIG); } @Override @@ -151,7 +150,7 @@ protected ForeignCallDescriptor postWriteBarrierCallDescriptor() { @Override protected boolean verifyOops() { - return GraalHotSpotVMConfigNode.verifyOops(); + return HotSpotReplacementsUtil.verifyOops(INJECTED_VMCONFIG); } @Override @@ -203,15 +202,15 @@ public Templates(OptionValues options, Iterable factories, this.lowerer = new HotspotG1WriteBarrierLowerer(config, factory); HotSpotG1WriteBarrierSnippets receiver = new HotSpotG1WriteBarrierSnippets(providers.getRegisters()); - g1PreWriteBarrier = snippet(G1WriteBarrierSnippets.class, "g1PreWriteBarrier", null, receiver, GC_INDEX_LOCATION, GC_LOG_LOCATION, SATB_QUEUE_MARKING_LOCATION, SATB_QUEUE_INDEX_LOCATION, + g1PreWriteBarrier = snippet(G1WriteBarrierSnippets.class, "g1PreWriteBarrier", null, receiver, SATB_QUEUE_LOG_LOCATION, SATB_QUEUE_MARKING_ACTIVE_LOCATION, SATB_QUEUE_INDEX_LOCATION, SATB_QUEUE_BUFFER_LOCATION); - g1ReferentReadBarrier = snippet(G1WriteBarrierSnippets.class, "g1ReferentReadBarrier", null, receiver, GC_INDEX_LOCATION, GC_LOG_LOCATION, SATB_QUEUE_MARKING_LOCATION, + g1ReferentReadBarrier = snippet(G1WriteBarrierSnippets.class, "g1ReferentReadBarrier", null, receiver, SATB_QUEUE_LOG_LOCATION, SATB_QUEUE_MARKING_ACTIVE_LOCATION, SATB_QUEUE_INDEX_LOCATION, SATB_QUEUE_BUFFER_LOCATION); - g1PostWriteBarrier = snippet(G1WriteBarrierSnippets.class, "g1PostWriteBarrier", null, receiver, GC_CARD_LOCATION, GC_INDEX_LOCATION, GC_LOG_LOCATION, CARD_QUEUE_INDEX_LOCATION, + g1PostWriteBarrier = snippet(G1WriteBarrierSnippets.class, "g1PostWriteBarrier", null, receiver, GC_CARD_LOCATION, CARD_QUEUE_LOG_LOCATION, CARD_QUEUE_INDEX_LOCATION, CARD_QUEUE_BUFFER_LOCATION); - g1ArrayRangePreWriteBarrier = snippet(G1WriteBarrierSnippets.class, "g1ArrayRangePreWriteBarrier", null, receiver, GC_INDEX_LOCATION, GC_LOG_LOCATION, SATB_QUEUE_MARKING_LOCATION, + g1ArrayRangePreWriteBarrier = snippet(G1WriteBarrierSnippets.class, "g1ArrayRangePreWriteBarrier", null, receiver, SATB_QUEUE_LOG_LOCATION, SATB_QUEUE_MARKING_ACTIVE_LOCATION, SATB_QUEUE_INDEX_LOCATION, SATB_QUEUE_BUFFER_LOCATION); - g1ArrayRangePostWriteBarrier = snippet(G1WriteBarrierSnippets.class, "g1ArrayRangePostWriteBarrier", null, receiver, GC_CARD_LOCATION, GC_INDEX_LOCATION, GC_LOG_LOCATION, + g1ArrayRangePostWriteBarrier = snippet(G1WriteBarrierSnippets.class, "g1ArrayRangePostWriteBarrier", null, receiver, GC_CARD_LOCATION, CARD_QUEUE_LOG_LOCATION, CARD_QUEUE_INDEX_LOCATION, CARD_QUEUE_BUFFER_LOCATION); } diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotInvocationPluginHelper.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotInvocationPluginHelper.java new file mode 100644 index 000000000000..2a14ce0712f7 --- /dev/null +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotInvocationPluginHelper.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.replacements; + +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.ARRAY_KLASS_COMPONENT_MIRROR; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_ARRAY_KLASS_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HOTSPOT_OOP_HANDLE_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_OSTHREAD_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_ACCESS_FLAGS_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_MODIFIER_FLAGS_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_SUPER_KLASS_LOCATION; +import static org.graalvm.word.LocationIdentity.any; + +import java.util.function.Function; + +import org.graalvm.compiler.core.common.type.ObjectStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.core.common.type.TypeReference; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode; +import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.NodeView; +import org.graalvm.compiler.nodes.PiNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.IsNullNode; +import org.graalvm.compiler.nodes.extended.GuardingNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.memory.OnHeapMemoryAccess.BarrierType; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; +import org.graalvm.compiler.nodes.type.StampTool; +import org.graalvm.compiler.replacements.InvocationPluginHelper; +import org.graalvm.word.LocationIdentity; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * A helper class for HotSpot specific invocation plugins. In particular it adds helpers for + * correctly performing reads of HotSpot specific fields. + */ +public class HotSpotInvocationPluginHelper extends InvocationPluginHelper { + + private final GraalHotSpotVMConfig config; + + public HotSpotInvocationPluginHelper(GraphBuilderContext b, ResolvedJavaMethod targetMethod, GraalHotSpotVMConfig config) { + super(b, targetMethod); + this.config = config; + } + + private Stamp getClassStamp(boolean nonNull) { + ResolvedJavaType toType = b.getMetaAccess().lookupJavaType(Class.class); + return StampFactory.object(TypeReference.createExactTrusted(toType), nonNull); + } + + public ValueNode readKlassFromClass(ValueNode clazz) { + return b.add(ClassGetHubNode.create(clazz, b.getMetaAccess(), b.getConstantReflection())); + } + + private ValueNode readLocation(ValueNode base, HotSpotVMConfigField field) { + return readLocation(base, field.getOffset(config), field.location, field.getStamp(getWordKind()), null); + } + + private ValueNode readLocation(ValueNode base, HotSpotVMConfigField field, Stamp stamp) { + assert field.getStamp(getWordKind()) == null; + return readLocation(base, field.getOffset(config), field.location, stamp, null); + } + + private ValueNode readLocation(ValueNode base, int offset, LocationIdentity location, Stamp stamp, GuardingNode guard) { + assert StampTool.isPointerNonNull(base) || base.stamp(NodeView.DEFAULT).getStackKind() == getWordKind() : "must be null guarded"; + AddressNode address = makeOffsetAddress(base, asWord(offset)); + ReadNode value = b.add(new ReadNode(address, location, stamp, BarrierType.NONE)); + ValueNode returnValue = ReadNode.canonicalizeRead(value, value.getAddress(), value.getLocationIdentity(), b, NodeView.DEFAULT); + if (value != returnValue) { + // We could clean up the dead nodes here + } else { + if (guard != null) { + value.setGuard(guard); + } + } + return b.add(returnValue); + } + + /** + * An abstraction for fields of {@link GraalHotSpotVMConfig}. + */ + enum HotSpotVMConfigField { + KLASS_MODIFIER_FLAGS_OFFSET(config -> config.klassModifierFlagsOffset, KLASS_MODIFIER_FLAGS_LOCATION, StampFactory.forKind(JavaKind.Int)), + KLASS_SUPER_KLASS_OFFSET(config -> config.klassSuperKlassOffset, KLASS_SUPER_KLASS_LOCATION, KlassPointerStamp.klass()), + CLASS_ARRAY_KLASS_OFFSET(config -> config.arrayKlassOffset, CLASS_ARRAY_KLASS_LOCATION, KlassPointerStamp.klassNonNull()), + OS_THREAD_INTERRUPTED_OFFSET(config -> config.osThreadInterruptedOffset, any(), StampFactory.forKind(JavaKind.Int)), + JAVA_THREAD_OSTHREAD_OFFSET(config -> config.osThreadOffset, JAVA_THREAD_OSTHREAD_LOCATION), + JAVA_THREAD_THREAD_OBJECT(config -> config.threadObjectOffset, JAVA_THREAD_THREAD_OBJECT_LOCATION, null), + KLASS_ACCESS_FLAGS_OFFSET(config -> config.klassAccessFlagsOffset, KLASS_ACCESS_FLAGS_LOCATION, StampFactory.forKind(JavaKind.Int)), + HOTSPOT_OOP_HANDLE_VALUE(config -> 0, HOTSPOT_OOP_HANDLE_LOCATION, StampFactory.forKind(JavaKind.Object)); + + private final Function getter; + private final LocationIdentity location; + + private final Stamp stamp; + private final boolean isWord; + + HotSpotVMConfigField(Function getter, LocationIdentity location, Stamp stamp) { + this.getter = getter; + this.location = location; + this.stamp = stamp; + this.isWord = false; + } + + HotSpotVMConfigField(Function getter, LocationIdentity location) { + this.getter = getter; + this.location = location; + this.stamp = null; + this.isWord = true; + } + + public int getOffset(GraalHotSpotVMConfig config) { + return getter.apply(config); + } + + public Stamp getStamp(JavaKind wordKind) { + if (isWord) { + return StampFactory.forKind(wordKind); + } + return stamp; + } + + } + + /** + * Read {@code Klass::_modifier_flags}. + */ + public ValueNode readKlassModifierFlags(ValueNode klass) { + return readLocation(klass, HotSpotVMConfigField.KLASS_MODIFIER_FLAGS_OFFSET); + } + + /** + * Read {@code Klass::_access_flags}. + */ + public ValueNode readKlassAccessFlags(ValueNode klass) { + return readLocation(klass, HotSpotVMConfigField.KLASS_ACCESS_FLAGS_OFFSET); + } + + /** + * Read {@code Klass:_layout_helper}. + */ + public ValueNode klassLayoutHelper(ValueNode klass) { + return b.add(KlassLayoutHelperNode.create(config, klass, b.getConstantReflection(), b.getMetaAccess())); + } + + /** + * Read {@code ArrayKlass::_component_mirror}. + */ + public ValueNode readArrayKlassComponentMirror(ValueNode klass, GuardingNode guard) { + int offset = config.getFieldOffset("ArrayKlass::_component_mirror", Integer.class, "oop"); + Stamp stamp = getClassStamp(true); + return readLocation(klass, offset, ARRAY_KLASS_COMPONENT_MIRROR, stamp, guard); + } + + /** + * Read {@code Klass::_super}. + */ + public ValueNode readKlassSuperKlass(PiNode klassNonNull) { + return readLocation(klassNonNull, HotSpotVMConfigField.KLASS_SUPER_KLASS_OFFSET); + } + + public PiNode emitNullReturnGuard(ValueNode klass, ValueNode returnValue, double probability) { + GuardingNode nonnullGuard = emitReturnIf(IsNullNode.create(klass), returnValue, probability); + return piCast(klass, nonnullGuard, KlassPointerStamp.klassNonNull()); + } + + /** + * Read the injected field {@code java.lang.Class.array_klass}. + */ + public ValueNode loadArrayKlass(ValueNode componentType) { + return readLocation(componentType, HotSpotVMConfigField.CLASS_ARRAY_KLASS_OFFSET); + } + + public ValueNode readCurrentThreadObject() { + return readCurrentThreadObject(b.add(new CurrentJavaThreadNode(getWordKind()))); + } + + public ValueNode readCurrentThreadObject(CurrentJavaThreadNode thread) { + // JavaThread::_threadObj is never compressed + ObjectStamp threadStamp = StampFactory.objectNonNull(TypeReference.create(b.getAssumptions(), b.getMetaAccess().lookupJavaType(Thread.class))); + Stamp fieldStamp = config.threadObjectFieldIsHandle ? StampFactory.forKind(getWordKind()) : threadStamp; + ValueNode value = readLocation(thread, HotSpotVMConfigField.JAVA_THREAD_THREAD_OBJECT, fieldStamp); + if (config.threadObjectFieldIsHandle) { + // Read the Object from the OopHandle + ValueNode handleOffset = ConstantNode.forIntegerKind(getWordKind(), 0, b.getGraph()); + AddressNode handleAddress = b.add(new OffsetAddressNode(value, handleOffset)); + value = b.add(new ReadNode(handleAddress, HOTSPOT_OOP_HANDLE_LOCATION, threadStamp, BarrierType.NONE)); + } + return value; + } + + /** + * Reads {@code JavaThread::_osthread}. + */ + public ValueNode readOsThread(CurrentJavaThreadNode thread) { + return readLocation(thread, HotSpotVMConfigField.JAVA_THREAD_OSTHREAD_OFFSET); + } + + /** + * Reads {@code OSThread::_interrupted}. + */ + public ValueNode readOsThreadInterrupted(ValueNode osThread) { + return readLocation(osThread, HotSpotVMConfigField.OS_THREAD_INTERRUPTED_OFFSET); + } +} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java index 0bca26b68f08..919ab65e0e22 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java @@ -39,9 +39,7 @@ import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node.ConstantNodeParameter; import org.graalvm.compiler.graph.Node.NodeIntrinsic; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode; import org.graalvm.compiler.hotspot.word.KlassPointer; import org.graalvm.compiler.nodes.CanonicalizableLocation; import org.graalvm.compiler.nodes.CompressionNode; @@ -59,10 +57,10 @@ import org.graalvm.compiler.nodes.memory.AddressableMemoryAccess; import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; +import org.graalvm.compiler.nodes.spi.CoreProviders; import org.graalvm.compiler.nodes.type.StampTool; import org.graalvm.compiler.replacements.ReplacementsUtil; import org.graalvm.compiler.replacements.nodes.ReadRegisterNode; -import org.graalvm.compiler.replacements.nodes.WriteRegisterNode; import org.graalvm.compiler.word.Word; import org.graalvm.word.LocationIdentity; import org.graalvm.word.WordFactory; @@ -93,7 +91,7 @@ abstract static class HotSpotOptimizingLocationIdentity extends NamedLocationIde } @Override - public abstract ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool); + public abstract ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CoreProviders tool); protected ValueNode findReadHub(ValueNode object) { ValueNode base = object; @@ -146,7 +144,7 @@ public static ResolvedJavaType methodHolderClass(@InjectedParameter IntrinsicCon } @Fold - static ResolvedJavaType getType(@Fold.InjectedParameter IntrinsicContext context, String typeName) { + public static ResolvedJavaType getType(@Fold.InjectedParameter IntrinsicContext context, String typeName) { try { UnresolvedJavaType unresolved = UnresolvedJavaType.create(typeName); return unresolved.resolve(methodHolderClass(context)); @@ -160,7 +158,7 @@ public static int getFieldOffset(ResolvedJavaType type, String fieldName) { return getField(type, fieldName).getOffset(); } - private static ResolvedJavaField getField(ResolvedJavaType type, String fieldName) { + public static ResolvedJavaField getField(ResolvedJavaType type, String fieldName) { for (ResolvedJavaField field : type.getInstanceFields(true)) { if (field.getName().equals(fieldName)) { return field; @@ -305,25 +303,8 @@ public static Object getPendingException(Word thread) { */ public static final LocationIdentity JAVA_THREAD_THREAD_OBJECT_LOCATION = NamedLocationIdentity.immutable("JavaThread::_threadObj"); - @Fold - public static int threadObjectOffset(@InjectedParameter GraalHotSpotVMConfig config) { - return config.threadObjectOffset; - } - public static final LocationIdentity JAVA_THREAD_OSTHREAD_LOCATION = NamedLocationIdentity.mutable("JavaThread::_osthread"); - @Fold - public static int osThreadOffset(@InjectedParameter GraalHotSpotVMConfig config) { - assert config.osThreadOffset != Integer.MAX_VALUE; - return config.osThreadOffset; - } - - @Fold - public static int osThreadInterruptedOffset(@InjectedParameter GraalHotSpotVMConfig config) { - assert config.osThreadInterruptedOffset != Integer.MAX_VALUE; - return config.osThreadInterruptedOffset; - } - @Fold public static JavaKind getWordKind() { return runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordJavaKind; @@ -353,16 +334,6 @@ public static int klassAccessFlagsOffset(@InjectedParameter GraalHotSpotVMConfig return config.klassAccessFlagsOffset; } - @Fold - public static int jvmAccWrittenFlags(@InjectedParameter GraalHotSpotVMConfig config) { - return config.jvmAccWrittenFlags; - } - - @Fold - public static int jvmAccIsHiddenClass(@InjectedParameter GraalHotSpotVMConfig config) { - return config.jvmAccIsHiddenClass; - } - @Fold public static int jvmAccHasFinalizer(@InjectedParameter GraalHotSpotVMConfig config) { return config.jvmAccHasFinalizer; @@ -370,7 +341,7 @@ public static int jvmAccHasFinalizer(@InjectedParameter GraalHotSpotVMConfig con public static final LocationIdentity KLASS_LAYOUT_HELPER_LOCATION = new HotSpotOptimizingLocationIdentity("Klass::_layout_helper") { @Override - public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) { + public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CoreProviders tool) { ValueNode javaObject = findReadHub(object); if (javaObject != null) { if (javaObject.stamp(NodeView.DEFAULT) instanceof ObjectStamp) { @@ -459,18 +430,8 @@ public static boolean klassIsArray(KlassPointer klassNonNull) { public static final LocationIdentity ARRAY_KLASS_COMPONENT_MIRROR = NamedLocationIdentity.immutable("ArrayKlass::_component_mirror"); - @Fold - public static int arrayKlassComponentMirrorOffset(@InjectedParameter GraalHotSpotVMConfig config) { - return config.getFieldOffset("ArrayKlass::_component_mirror", Integer.class, "oop"); - } - public static final LocationIdentity KLASS_SUPER_KLASS_LOCATION = NamedLocationIdentity.immutable("Klass::_super"); - @Fold - public static int klassSuperKlassOffset(@InjectedParameter GraalHotSpotVMConfig config) { - return config.klassSuperKlassOffset; - } - public static final LocationIdentity MARK_WORD_LOCATION = NamedLocationIdentity.mutable("MarkWord"); @Fold @@ -482,7 +443,7 @@ public static int markOffset(@InjectedParameter GraalHotSpotVMConfig config) { public static final LocationIdentity HUB_LOCATION = new HotSpotOptimizingLocationIdentity("Hub") { @Override - public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) { + public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CoreProviders tool) { TypeReference constantType = StampTool.typeReferenceOrNull(object); if (constantType != null && constantType.isExact()) { return ConstantNode.forConstant(read.stamp(NodeView.DEFAULT), tool.getConstantReflection().asObjectHub(constantType.getType()), tool.getMetaAccess()); @@ -493,7 +454,7 @@ public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNod public static final LocationIdentity COMPRESSED_HUB_LOCATION = new HotSpotOptimizingLocationIdentity("CompressedHub") { @Override - public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) { + public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CoreProviders tool) { TypeReference constantType = StampTool.typeReferenceOrNull(object); if (constantType != null && constantType.isExact()) { return ConstantNode.forConstant(read.stamp(NodeView.DEFAULT), ((HotSpotMetaspaceConstant) tool.getConstantReflection().asObjectHub(constantType.getType())).compress(), @@ -640,6 +601,11 @@ public static int cardTableShift(@InjectedParameter GraalHotSpotVMConfig config) return config.cardtableShift; } + @Fold + public static long cardTableStart(@InjectedParameter GraalHotSpotVMConfig config) { + return config.cardtableStartAddress; + } + @Fold public static int g1CardQueueIndexOffset(@InjectedParameter GraalHotSpotVMConfig config) { return config.g1CardQueueIndexOffset; @@ -651,8 +617,13 @@ public static int g1CardQueueBufferOffset(@InjectedParameter GraalHotSpotVMConfi } @Fold - public static int g1SATBQueueMarkingOffset(@InjectedParameter GraalHotSpotVMConfig config) { - return config.g1SATBQueueMarkingOffset; + public static int logOfHeapRegionGrainBytes(@InjectedParameter GraalHotSpotVMConfig config) { + return config.logOfHRGrainBytes; + } + + @Fold + public static int g1SATBQueueMarkingActiveOffset(@InjectedParameter GraalHotSpotVMConfig config) { + return config.g1SATBQueueMarkingActiveOffset; } @Fold @@ -725,13 +696,33 @@ public static KlassPointer loadHub(Object object) { return loadHubIntrinsic(object); } + @Fold + public static boolean verifyOops(@InjectedParameter GraalHotSpotVMConfig config) { + return config.verifyOops; + } + public static Object verifyOop(Object object) { - if (GraalHotSpotVMConfigNode.verifyOops()) { + if (verifyOops(INJECTED_VMCONFIG)) { verifyOopStub(VERIFY_OOP, object); } return object; } + @Fold + public static long verifyOopBits(@InjectedParameter GraalHotSpotVMConfig config) { + return config.verifyOopBits; + } + + @Fold + public static long verifyOopMask(@InjectedParameter GraalHotSpotVMConfig config) { + return config.verifyOopMask; + } + + @Fold + public static long verifyOopCounterAddress(@InjectedParameter GraalHotSpotVMConfig config) { + return config.verifyOopCounterAddress; + } + @NodeIntrinsic(ForeignCallNode.class) private static native Object verifyOopStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object); @@ -763,9 +754,6 @@ public static Word registerAsWord(@ConstantNodeParameter Register register) { @NodeIntrinsic(value = ReadRegisterNode.class) public static native Word registerAsWord(@ConstantNodeParameter Register register, @ConstantNodeParameter boolean directUse, @ConstantNodeParameter boolean incoming); - @NodeIntrinsic(value = WriteRegisterNode.class) - public static native void writeRegisterAsWord(@ConstantNodeParameter Register register, Word value); - @NodeIntrinsic(value = RawLoadNode.class) private static native Word loadWordFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter LocationIdentity locationIdentity, @ConstantNodeParameter JavaKind wordKind); @@ -830,14 +818,14 @@ public static int klassModifierFlagsOffset(@InjectedParameter GraalHotSpotVMConf public static final LocationIdentity CLASS_KLASS_LOCATION = new HotSpotOptimizingLocationIdentity("Class._klass") { @Override - public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) { + public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CoreProviders tool) { return foldIndirection(read, object, CLASS_MIRROR_LOCATION); } }; public static final LocationIdentity CLASS_ARRAY_KLASS_LOCATION = new HotSpotOptimizingLocationIdentity("Class._array_klass") { @Override - public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) { + public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CoreProviders tool) { return foldIndirection(read, object, ARRAY_KLASS_COMPONENT_MIRROR); } }; @@ -903,7 +891,7 @@ public static ResolvedJavaType referenceType(@InjectedParameter MetaAccessProvid public static final LocationIdentity OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION = new HotSpotOptimizingLocationIdentity("ObjArrayKlass::_element_klass") { @Override - public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) { + public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CoreProviders tool) { ValueNode javaObject = findReadHub(object); if (javaObject != null) { ResolvedJavaType type = StampTool.typeOrNull(javaObject); diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotSerialWriteBarrierSnippets.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotSerialWriteBarrierSnippets.java index 6fd4241f0568..01b7955bb998 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotSerialWriteBarrierSnippets.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotSerialWriteBarrierSnippets.java @@ -28,7 +28,6 @@ import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; -import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode; import org.graalvm.compiler.nodes.gc.SerialArrayRangeWriteBarrier; import org.graalvm.compiler.nodes.gc.SerialWriteBarrier; import org.graalvm.compiler.nodes.spi.LoweringTool; @@ -50,7 +49,7 @@ public HotSpotSerialWriteBarrierSnippets() { @Override public Word cardTableAddress() { - return WordFactory.unsigned(GraalHotSpotVMConfigNode.cardTableAddress()); + return WordFactory.unsigned(HotSpotReplacementsUtil.cardTableStart(INJECTED_VMCONFIG)); } @Override diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HubGetClassNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HubGetClassNode.java index 128c29044168..bfd277389fe1 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HubGetClassNode.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HubGetClassNode.java @@ -27,7 +27,6 @@ import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; -import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.TypeReference; import org.graalvm.compiler.graph.Node; @@ -74,7 +73,7 @@ public Node canonical(CanonicalizerTool tool) { return null; } else { MetaAccessProvider metaAccess = tool.getMetaAccess(); - if (metaAccess != null && hub.isConstant() && !GraalOptions.ImmutableCode.getValue(tool.getOptions())) { + if (metaAccess != null && hub.isConstant()) { ResolvedJavaType exactType = tool.getConstantReflection().asJavaType(hub.asConstant()); if (exactType != null) { return ConstantNode.forConstant(tool.getConstantReflection().asJavaClass(exactType), metaAccess); diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/InstanceOfSnippets.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/InstanceOfSnippets.java index 49554a1b8ca4..b5e16370e046 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/InstanceOfSnippets.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/InstanceOfSnippets.java @@ -26,7 +26,6 @@ import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile; import static jdk.vm.ci.meta.DeoptimizationReason.OptimizedTypeCheckViolated; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.PRIMARY_SUPERS_LOCATION; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.SECONDARY_SUPER_CACHE_LOCATION; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadHubIntrinsic; @@ -275,11 +274,6 @@ protected Arguments makeArguments(InstanceOfUsageReplacer replacer, LoweringTool OptionValues localOptions = instanceOf.getOptions(); JavaTypeProfile profile = instanceOf.profile(); - if (GeneratePIC.getValue(localOptions)) { - // FIXME: We can't embed constants in hints. We can't really load them from GOT - // either. Hard problem. - profile = null; - } TypeCheckHints hintInfo = new TypeCheckHints(instanceOf.type(), profile, assumptions, TypeCheckMinProfileHitProbability.getValue(localOptions), TypeCheckMaxHints.getValue(localOptions)); final HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) instanceOf.type().getType(); diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java index 978eb479e6d4..6a9fb0338252 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java @@ -99,6 +99,7 @@ public void lower(LoadExceptionObjectNode loadExceptionObject, HotSpotRegistersP graph.addBeforeFixed(loadExceptionObject, thread); ForeignCallNode loadExceptionC = graph.add(new ForeignCallNode(LOAD_AND_CLEAR_EXCEPTION, thread)); loadExceptionC.setStateAfter(loadExceptionObject.stateAfter()); + loadExceptionC.computeStateDuring(loadExceptionObject.stateAfter()); graph.replaceFixedWithFixed(loadExceptionObject, loadExceptionC); } else { Arguments args = new Arguments(loadException, loadExceptionObject.graph().getGuardsStage(), tool.getLoweringStage()); diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionSubstitutions.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionSubstitutions.java deleted file mode 100644 index 178f8b84a1a1..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionSubstitutions.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.replacements; - -import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_ACCESS_FLAGS_LOCATION; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.jvmAccWrittenFlags; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.klassAccessFlagsOffset; - -import java.lang.reflect.Modifier; - -import org.graalvm.compiler.api.directives.GraalDirectives; -import org.graalvm.compiler.api.replacements.ClassSubstitution; -import org.graalvm.compiler.api.replacements.MethodSubstitution; -import org.graalvm.compiler.hotspot.word.KlassPointer; - -/** - * Substitutions for {@code sun.reflect.Reflection} methods. - */ -@ClassSubstitution(className = {"jdk.internal.reflect.Reflection", "sun.reflect.Reflection"}, optional = true) -public class ReflectionSubstitutions { - - @MethodSubstitution - public static int getClassAccessFlags(Class aClass) { - KlassPointer klass = ClassGetHubNode.readClass(GraalDirectives.guardingNonNull(aClass)); - if (klass.isNull()) { - // Class for primitive type - return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC; - } else { - return klass.readInt(klassAccessFlagsOffset(INJECTED_VMCONFIG), KLASS_ACCESS_FLAGS_LOCATION) & jvmAccWrittenFlags(INJECTED_VMCONFIG); - } - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ThreadSubstitutions.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ThreadSubstitutions.java deleted file mode 100644 index ddf93e331c04..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ThreadSubstitutions.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.replacements; - -import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_OSTHREAD_LOCATION; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.osThreadInterruptedOffset; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.osThreadOffset; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.threadObjectOffset; -import static org.graalvm.word.LocationIdentity.any; - -import org.graalvm.compiler.api.replacements.ClassSubstitution; -import org.graalvm.compiler.api.replacements.MethodSubstitution; -import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode; -import org.graalvm.compiler.word.Word; - -/** - * Substitutions for {@link java.lang.Thread} methods. - */ -@ClassSubstitution(Thread.class) -public class ThreadSubstitutions { - - /** - * hidden in 9. - */ - @MethodSubstitution(isStatic = false, optional = true) - public static boolean isInterrupted(final Thread thisObject, boolean clearInterrupted) { - Word javaThread = CurrentJavaThreadNode.get(); - Object thread = javaThread.readObject(threadObjectOffset(INJECTED_VMCONFIG), JAVA_THREAD_THREAD_OBJECT_LOCATION); - if (thisObject == thread) { - Word osThread = javaThread.readWord(osThreadOffset(INJECTED_VMCONFIG), JAVA_THREAD_OSTHREAD_LOCATION); - boolean interrupted = osThread.readInt(osThreadInterruptedOffset(INJECTED_VMCONFIG), any()) != 0; - if (!interrupted || !clearInterrupted) { - return interrupted; - } - } - return isInterrupted(thisObject, clearInterrupted); - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeCopyMemoryNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeCopyMemoryNode.java index e4d98f92c5db..be4063ea21bd 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeCopyMemoryNode.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeCopyMemoryNode.java @@ -29,7 +29,6 @@ import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16; import org.graalvm.compiler.core.common.type.StampFactory; -import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.AbstractStateSplit; @@ -53,7 +52,7 @@ public class UnsafeCopyMemoryNode extends AbstractStateSplit implements Lowerabl @Input ValueNode desOffset; @Input ValueNode bytes; - @OptionalInput(Memory) Node lastLocationAccess; + @OptionalInput(Memory) MemoryKill lastLocationAccess; private final boolean guarded; @@ -85,14 +84,13 @@ public LocationIdentity getLocationIdentity() { @Override public MemoryKill getLastLocationAccess() { - return (MemoryKill) lastLocationAccess; + return lastLocationAccess; } @Override public void setLastLocationAccess(MemoryKill lla) { - Node newLla = ValueNodeUtil.asNode(lla); - updateUsages(lastLocationAccess, newLla); - lastLocationAccess = newLla; + updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(lla)); + lastLocationAccess = lla; } @NodeIntrinsic diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java deleted file mode 100644 index f4628bca004e..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.replacements.aot; - -import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.VERY_SLOW_PATH_PROBABILITY; -import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; -import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; - -import org.graalvm.compiler.api.replacements.Snippet; -import org.graalvm.compiler.debug.DebugHandlersFactory; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; -import org.graalvm.compiler.hotspot.meta.HotSpotProviders; -import org.graalvm.compiler.hotspot.nodes.aot.EncodedSymbolNode; -import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; -import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassStubCall; -import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode; -import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersIndirectlyNode; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantStubCall; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicStubCall; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode; -import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersStubCall; -import org.graalvm.compiler.hotspot.nodes.type.MethodPointerStamp; -import org.graalvm.compiler.hotspot.word.KlassPointer; -import org.graalvm.compiler.hotspot.word.MethodCountersPointer; -import org.graalvm.compiler.hotspot.word.MethodPointer; -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.replacements.SnippetTemplate; -import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates; -import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; -import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; -import org.graalvm.compiler.replacements.Snippets; - -import jdk.vm.ci.code.TargetDescription; -import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; -import jdk.vm.ci.hotspot.HotSpotObjectConstant; -import jdk.vm.ci.meta.Constant; - -public class ResolveConstantSnippets implements Snippets { - - @Snippet - public static Object resolveObjectConstant(Object constant) { - Object result = LoadConstantIndirectlyNode.loadObject(constant); - if (probability(VERY_SLOW_PATH_PROBABILITY, result == null)) { - result = ResolveConstantStubCall.resolveObject(constant, EncodedSymbolNode.encode(constant)); - } - return result; - } - - @Snippet - public static Object resolveDynamicConstant(Object constant) { - Object result = LoadConstantIndirectlyNode.loadObject(constant); - if (probability(VERY_SLOW_PATH_PROBABILITY, result == null)) { - result = ResolveDynamicStubCall.resolveInvoke(constant); - } - return result; - } - - @Snippet - public static KlassPointer resolveKlassConstant(KlassPointer constant) { - KlassPointer result = LoadConstantIndirectlyNode.loadKlass(constant); - if (probability(VERY_SLOW_PATH_PROBABILITY, result.isNull())) { - result = ResolveConstantStubCall.resolveKlass(constant, EncodedSymbolNode.encode(constant)); - } - return result; - } - - @Snippet - public static MethodCountersPointer resolveMethodAndLoadCounters(MethodPointer method, KlassPointer klassHint) { - MethodCountersPointer result = LoadMethodCountersIndirectlyNode.loadMethodCounters(method); - if (probability(VERY_SLOW_PATH_PROBABILITY, result.isNull())) { - result = ResolveMethodAndLoadCountersStubCall.resolveMethodAndLoadCounters(method, klassHint, EncodedSymbolNode.encode(method)); - } - return result; - } - - @Snippet - public static KlassPointer initializeKlass(KlassPointer constant) { - KlassPointer result = LoadConstantIndirectlyNode.loadKlass(constant, HotSpotConstantLoadAction.INITIALIZE); - if (probability(VERY_SLOW_PATH_PROBABILITY, result.isNull())) { - result = InitializeKlassStubCall.initializeKlass(constant, EncodedSymbolNode.encode(constant)); - } - return result; - } - - @Snippet - public static KlassPointer pureInitializeKlass(KlassPointer constant) { - KlassPointer result = LoadConstantIndirectlyNode.loadKlass(constant, HotSpotConstantLoadAction.INITIALIZE); - if (probability(VERY_SLOW_PATH_PROBABILITY, result.isNull())) { - result = ResolveConstantStubCall.resolveKlass(constant, EncodedSymbolNode.encode(constant), HotSpotConstantLoadAction.INITIALIZE); - } - return result; - } - - public static class Templates extends AbstractTemplates { - private final SnippetInfo resolveObjectConstant = snippet(ResolveConstantSnippets.class, "resolveObjectConstant"); - private final SnippetInfo resolveDynamicConstant = snippet(ResolveConstantSnippets.class, "resolveDynamicConstant"); - private final SnippetInfo resolveKlassConstant = snippet(ResolveConstantSnippets.class, "resolveKlassConstant"); - private final SnippetInfo resolveMethodAndLoadCounters = snippet(ResolveConstantSnippets.class, "resolveMethodAndLoadCounters"); - private final SnippetInfo initializeKlass = snippet(ResolveConstantSnippets.class, "initializeKlass"); - private final SnippetInfo pureInitializeKlass = snippet(ResolveConstantSnippets.class, "pureInitializeKlass"); - - public Templates(OptionValues options, Iterable factories, HotSpotProviders providers, TargetDescription target) { - super(options, factories, providers, providers.getSnippetReflection(), target); - } - - public void lower(ResolveDynamicConstantNode resolveConstantNode, LoweringTool tool) { - StructuredGraph graph = resolveConstantNode.graph(); - - ValueNode value = resolveConstantNode.value(); - assert value.isConstant() : "Expected a constant: " + value; - SnippetInfo snippet = resolveDynamicConstant; - - Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); - args.add("constant", value); - - SnippetTemplate template = template(resolveConstantNode, args); - template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, args); - - assert resolveConstantNode.hasNoUsages(); - if (!resolveConstantNode.isDeleted()) { - GraphUtil.killWithUnusedFloatingInputs(resolveConstantNode); - } - } - - public void lower(ResolveConstantNode resolveConstantNode, LoweringTool tool) { - StructuredGraph graph = resolveConstantNode.graph(); - - ValueNode value = resolveConstantNode.value(); - assert value.isConstant() : "Expected a constant: " + value; - Constant constant = value.asConstant(); - SnippetInfo snippet = null; - - if (constant instanceof HotSpotMetaspaceConstant) { - HotSpotMetaspaceConstant hotspotMetaspaceConstant = (HotSpotMetaspaceConstant) constant; - if (hotspotMetaspaceConstant.asResolvedJavaType() != null) { - if (resolveConstantNode.action() == HotSpotConstantLoadAction.RESOLVE) { - snippet = resolveKlassConstant; - } else { - assert resolveConstantNode.action() == HotSpotConstantLoadAction.INITIALIZE; - snippet = pureInitializeKlass; - } - } - } else if (constant instanceof HotSpotObjectConstant) { - snippet = resolveObjectConstant; - HotSpotObjectConstant hotspotObjectConstant = (HotSpotObjectConstant) constant; - assert hotspotObjectConstant.isInternedString(); - } - if (snippet == null) { - throw new GraalError("Unsupported constant type: " + constant); - } - - Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); - args.add("constant", value); - - SnippetTemplate template = template(resolveConstantNode, args); - template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, args); - - assert resolveConstantNode.hasNoUsages(); - if (!resolveConstantNode.isDeleted()) { - GraphUtil.killWithUnusedFloatingInputs(resolveConstantNode); - } - } - - public void lower(InitializeKlassNode initializeKlassNode, LoweringTool tool) { - StructuredGraph graph = initializeKlassNode.graph(); - - ValueNode value = initializeKlassNode.value(); - assert value.isConstant() : "Expected a constant: " + value; - Constant constant = value.asConstant(); - - if (constant instanceof HotSpotMetaspaceConstant) { - Arguments args = new Arguments(initializeKlass, graph.getGuardsStage(), tool.getLoweringStage()); - args.add("constant", value); - - SnippetTemplate template = template(initializeKlassNode, args); - template.instantiate(providers.getMetaAccess(), initializeKlassNode, DEFAULT_REPLACER, args); - assert initializeKlassNode.hasNoUsages(); - if (!initializeKlassNode.isDeleted()) { - GraphUtil.killWithUnusedFloatingInputs(initializeKlassNode); - } - - } else { - throw new GraalError("Unsupported constant type: " + constant); - } - } - - public void lower(ResolveMethodAndLoadCountersNode resolveMethodAndLoadCountersNode, LoweringTool tool) { - StructuredGraph graph = resolveMethodAndLoadCountersNode.graph(); - ConstantNode method = ConstantNode.forConstant(MethodPointerStamp.methodNonNull(), resolveMethodAndLoadCountersNode.getMethod().getEncoding(), tool.getMetaAccess(), graph); - Arguments args = new Arguments(resolveMethodAndLoadCounters, graph.getGuardsStage(), tool.getLoweringStage()); - args.add("method", method); - args.add("klassHint", resolveMethodAndLoadCountersNode.getHub()); - SnippetTemplate template = template(resolveMethodAndLoadCountersNode, args); - template.instantiate(providers.getMetaAccess(), resolveMethodAndLoadCountersNode, DEFAULT_REPLACER, args); - - assert resolveMethodAndLoadCountersNode.hasNoUsages(); - if (!resolveMethodAndLoadCountersNode.isDeleted()) { - GraphUtil.killWithUnusedFloatingInputs(resolveMethodAndLoadCountersNode); - } - } - } -} diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/CheckcastArrayCopyCallNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java similarity index 93% rename from compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/CheckcastArrayCopyCallNode.java rename to compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java index 6c996eb0229e..ab358f9024b9 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/CheckcastArrayCopyCallNode.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java @@ -23,7 +23,7 @@ * questions. */ //JaCoCo Exclude -package org.graalvm.compiler.replacements.arraycopy; +package org.graalvm.compiler.hotspot.replacements.arraycopy; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; @@ -32,6 +32,7 @@ import org.graalvm.compiler.core.common.type.PrimitiveStamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; import org.graalvm.compiler.nodeinfo.InputType; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ConstantNode; @@ -49,6 +50,8 @@ import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.replacements.arraycopy.ArrayCopyCallNode; +import org.graalvm.compiler.replacements.arraycopy.ArrayCopyForeignCalls; import org.graalvm.compiler.word.Word; import org.graalvm.compiler.word.WordTypes; import org.graalvm.word.LocationIdentity; @@ -60,7 +63,8 @@ * Implements {@link System#arraycopy} via a {@linkplain ForeignCallNode stub call} that performs a * fast {@code CHECKCAST} check. * - * The target of the call is queried via {@link ArrayCopyLookup#lookupCheckcastArraycopyDescriptor}. + * The target of the call is queried via + * {@link HotSpotHostForeignCallsProvider#lookupCheckcastArraycopyDescriptor}. * * Instead of throwing an {@link ArrayStoreException}, the stub is expected to return the number of * copied elements xor'd with {@code -1}. Users of this node are responsible for converting that @@ -76,7 +80,7 @@ public final class CheckcastArrayCopyCallNode extends AbstractMemoryCheckpoint i public static final NodeClass TYPE = NodeClass.create(CheckcastArrayCopyCallNode.class); - private final ArrayCopyForeignCalls foreignCalls; + private final HotSpotHostForeignCallsProvider foreignCalls; private final JavaKind wordKind; @Input ValueNode src; @@ -94,7 +98,7 @@ protected CheckcastArrayCopyCallNode(@InjectedNodeParameter ArrayCopyForeignCall ValueNode destPos, ValueNode length, ValueNode superCheckOffset, ValueNode destElemKlass, boolean uninit) { super(TYPE, StampFactory.forKind(JavaKind.Int)); - this.foreignCalls = foreignCalls; + this.foreignCalls = (HotSpotHostForeignCallsProvider) foreignCalls; this.wordKind = wordTypes.getWordKind(); this.src = src; this.srcPos = srcPos; diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/GenericArrayCopyCallNode.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/GenericArrayCopyCallNode.java similarity index 92% rename from compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/GenericArrayCopyCallNode.java rename to compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/GenericArrayCopyCallNode.java index 2cc41f6a59d3..57b179381d89 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/GenericArrayCopyCallNode.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/GenericArrayCopyCallNode.java @@ -23,15 +23,16 @@ * questions. */ //JaCoCo Exclude -package org.graalvm.compiler.replacements.arraycopy; +package org.graalvm.compiler.hotspot.replacements.arraycopy; +import static org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider.GENERIC_ARRAYCOPY; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; -import static org.graalvm.compiler.replacements.arraycopy.ArrayCopyForeignCalls.GENERIC_ARRAYCOPY; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; import org.graalvm.compiler.nodeinfo.InputType; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.GetObjectAddressNode; @@ -42,13 +43,14 @@ import org.graalvm.compiler.nodes.memory.SingleMemoryKill; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.replacements.arraycopy.ArrayCopyCallNode; import org.graalvm.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; /** * Implements {@link System#arraycopy} via a {@link ForeignCallNode call} to a - * {@linkplain ArrayCopyLookup#GENERIC_ARRAYCOPY generic stub}. + * {@linkplain HotSpotHostForeignCallsProvider#GENERIC_ARRAYCOPY generic stub}. * * Instead of throwing an {@link ArrayStoreException}, the stub is expected to return the number of * copied elements xor'd with {@code -1}. Users of this node are responsible for converting that diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/HotSpotArraycopySnippets.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/HotSpotArraycopySnippets.java index 0bc3530f26d4..573ebaa88924 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/HotSpotArraycopySnippets.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/HotSpotArraycopySnippets.java @@ -43,14 +43,12 @@ import org.graalvm.compiler.replacements.ReplacementsUtil; import org.graalvm.compiler.replacements.arraycopy.ArrayCopyCallNode; import org.graalvm.compiler.replacements.arraycopy.ArrayCopySnippets; -import org.graalvm.compiler.replacements.arraycopy.CheckcastArrayCopyCallNode; import org.graalvm.compiler.word.Word; import org.graalvm.word.LocationIdentity; import org.graalvm.word.Pointer; import org.graalvm.word.WordFactory; import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.MetaAccessProvider; public class HotSpotArraycopySnippets extends ArrayCopySnippets { @@ -92,10 +90,9 @@ protected int heapWordSize() { } @Override - protected void doExactArraycopyWithSlowPathWork(Object src, int srcPos, Object dest, int destPos, int length, JavaKind elementKind, LocationIdentity arrayLocation, Counters counters, - MetaAccessProvider metaAccess) { - int scale = ReplacementsUtil.arrayIndexScale(metaAccess, elementKind); - int arrayBaseOffset = ReplacementsUtil.getArrayBaseOffset(metaAccess, elementKind); + protected void doExactArraycopyWithExpandedLoopSnippet(Object src, int srcPos, Object dest, int destPos, int length, JavaKind elementKind, LocationIdentity arrayLocation, Counters counters) { + int scale = ReplacementsUtil.arrayIndexScale(INJECTED_META_ACCESS, elementKind); + int arrayBaseOffset = ReplacementsUtil.getArrayBaseOffset(INJECTED_META_ACCESS, elementKind); long sourceOffset = arrayBaseOffset + (long) srcPos * scale; long destOffset = arrayBaseOffset + (long) destPos * scale; @@ -116,7 +113,7 @@ protected void doExactArraycopyWithSlowPathWork(Object src, int srcPos, Object d @Override @SuppressWarnings("unused") - protected void doCheckcastArraycopyWithSlowPathWork(Object src, int srcPos, Object dest, int destPos, int length, JavaKind elementKind, LocationIdentity arrayLocation, Counters counters) { + protected void doCheckcastArraycopySnippet(Object src, int srcPos, Object dest, int destPos, int length, JavaKind elementKind, LocationIdentity arrayLocation, Counters counters) { if (probability(FREQUENT_PROBABILITY, length > 0)) { Object nonNullSrc = PiNode.asNonNullObject(src); Object nonNullDest = PiNode.asNonNullObject(dest); @@ -146,4 +143,19 @@ protected void doCheckcastArraycopyWithSlowPathWork(Object src, int srcPos, Obje } } } + + @Override + protected void doGenericArraycopySnippet(Object src, int srcPos, Object dest, int destPos, int length, JavaKind elementKind, LocationIdentity arrayLocation, Counters counters) { + counters.genericArraycopyDifferentTypeCounter.inc(); + counters.genericArraycopyDifferentTypeCopiedCounter.add(length); + int copiedElements = GenericArrayCopyCallNode.genericArraycopy(src, srcPos, dest, destPos, length); + if (probability(SLOW_PATH_PROBABILITY, copiedElements != 0)) { + /* + * the stub doesn't throw the ArrayStoreException, but returns the number of copied + * elements (xor'd with -1). + */ + copiedElements ^= -1; + System.arraycopy(src, srcPos + copiedElements, dest, destPos + copiedElements, length - copiedElements); + } + } } diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProbabilisticProfileSnippets.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProbabilisticProfileSnippets.java deleted file mode 100644 index 2e36c480921c..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProbabilisticProfileSnippets.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.replacements.profiling; - -import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.backedgeCounterOffset; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.invocationCounterIncrement; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.invocationCounterOffset; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.invocationCounterShift; -import static org.graalvm.compiler.hotspot.replacements.profiling.ProfileSnippets.METHOD_COUNTERS; -import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY; -import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; -import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; - -import org.graalvm.compiler.api.replacements.Snippet; -import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; -import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; -import org.graalvm.compiler.debug.DebugHandlersFactory; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.graph.Node.ConstantNodeParameter; -import org.graalvm.compiler.graph.Node.NodeIntrinsic; -import org.graalvm.compiler.hotspot.HotSpotBackend; -import org.graalvm.compiler.hotspot.meta.HotSpotProviders; -import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode; -import org.graalvm.compiler.hotspot.nodes.profiling.ProfileBranchNode; -import org.graalvm.compiler.hotspot.nodes.profiling.ProfileInvokeNode; -import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode; -import org.graalvm.compiler.hotspot.word.MethodCountersPointer; -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.extended.ForeignCallNode; -import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.replacements.SnippetTemplate; -import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates; -import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; -import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; -import org.graalvm.compiler.replacements.Snippets; - -import jdk.vm.ci.code.CodeUtil; -import jdk.vm.ci.code.TargetDescription; - -public class ProbabilisticProfileSnippets implements Snippets { - @Snippet - public static boolean shouldProfile(@ConstantParameter int probLog, int random) { - int probabilityMask = (1 << probLog) - 1; - return (random & probabilityMask) == 0; - } - - @Snippet - public static int notificationMask(int freqLog, int probLog, int stepLog) { - int frequencyMask = (1 << freqLog) - 1; - int stepMask = (1 << (stepLog + probLog)) - 1; - return frequencyMask & ~stepMask; - } - - @NodeIntrinsic(ForeignCallNode.class) - public static native void methodInvocationEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters); - - @Snippet - public static void profileMethodEntryWithProbability(MethodCountersPointer counters, int random, int step, int stepLog, @ConstantParameter int freqLog, @ConstantParameter int probLog) { - if (probability(1.0 / (1 << probLog), shouldProfile(probLog, random))) { - int counterValue = counters.readInt(invocationCounterOffset(INJECTED_VMCONFIG), METHOD_COUNTERS) + ((invocationCounterIncrement(INJECTED_VMCONFIG) * step) << probLog); - counters.writeIntSideEffectFree(invocationCounterOffset(INJECTED_VMCONFIG), counterValue, METHOD_COUNTERS); - if (freqLog >= 0) { - int mask = notificationMask(freqLog, probLog, stepLog); - if (probability(SLOW_PATH_PROBABILITY, (counterValue & (mask << invocationCounterShift(INJECTED_VMCONFIG))) == 0)) { - methodInvocationEvent(HotSpotBackend.INVOCATION_EVENT, counters); - } - } - } - } - - @NodeIntrinsic(ForeignCallNode.class) - public static native void methodBackedgeEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters, int bci, int targetBci); - - @Snippet - public static void profileBackedgeWithProbability(MethodCountersPointer counters, int random, int step, int stepLog, @ConstantParameter int freqLog, @ConstantParameter int probLog, int bci, - int targetBci) { - if (probability(1.0 / (1 << probLog), shouldProfile(probLog, random))) { - int counterValue = counters.readInt(backedgeCounterOffset(INJECTED_VMCONFIG), METHOD_COUNTERS) + ((invocationCounterIncrement(INJECTED_VMCONFIG) * step) << probLog); - counters.writeIntSideEffectFree(backedgeCounterOffset(INJECTED_VMCONFIG), counterValue, METHOD_COUNTERS); - int mask = notificationMask(freqLog, probLog, stepLog); - if (probability(SLOW_PATH_PROBABILITY, (counterValue & (mask << invocationCounterShift(INJECTED_VMCONFIG))) == 0)) { - methodBackedgeEvent(HotSpotBackend.BACKEDGE_EVENT, counters, bci, targetBci); - } - } - } - - @Snippet - public static void profileConditionalBackedgeWithProbability(MethodCountersPointer counters, int random, int step, int stepLog, @ConstantParameter int freqLog, - @ConstantParameter int probLog, boolean branchCondition, - int bci, int targetBci) { - if (branchCondition) { - profileBackedgeWithProbability(counters, random, step, stepLog, freqLog, probLog, bci, targetBci); - } - } - - public static class Templates extends AbstractTemplates { - private final SnippetInfo profileMethodEntryWithProbability = snippet(ProbabilisticProfileSnippets.class, "profileMethodEntryWithProbability"); - private final SnippetInfo profileBackedgeWithProbability = snippet(ProbabilisticProfileSnippets.class, "profileBackedgeWithProbability"); - private final SnippetInfo profileConditionalBackedgeWithProbability = snippet(ProbabilisticProfileSnippets.class, "profileConditionalBackedgeWithProbability"); - - public Templates(OptionValues options, Iterable factories, HotSpotProviders providers, TargetDescription target) { - super(options, factories, providers, providers.getSnippetReflection(), target); - } - - public void lower(ProfileNode profileNode, LoweringTool tool) { - assert profileNode.getRandom() != null; - - StructuredGraph graph = profileNode.graph(); - LoadMethodCountersNode counters = graph.unique(new LoadMethodCountersNode(profileNode.getProfiledMethod())); - ConstantNode step = ConstantNode.forInt(profileNode.getStep(), graph); - ConstantNode stepLog = ConstantNode.forInt(CodeUtil.log2(profileNode.getStep()), graph); - - if (profileNode instanceof ProfileBranchNode) { - // Backedge event - ProfileBranchNode profileBranchNode = (ProfileBranchNode) profileNode; - SnippetInfo snippet = profileBranchNode.hasCondition() ? profileConditionalBackedgeWithProbability : profileBackedgeWithProbability; - Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); - ConstantNode bci = ConstantNode.forInt(profileBranchNode.bci(), graph); - ConstantNode targetBci = ConstantNode.forInt(profileBranchNode.targetBci(), graph); - - args.add("counters", counters); - args.add("random", profileBranchNode.getRandom()); - args.add("step", step); - args.add("stepLog", stepLog); - args.addConst("freqLog", profileBranchNode.getNotificationFreqLog()); - args.addConst("probLog", profileBranchNode.getProbabilityLog()); - if (profileBranchNode.hasCondition()) { - args.add("branchCondition", profileBranchNode.branchCondition()); - } - args.add("bci", bci); - args.add("targetBci", targetBci); - - SnippetTemplate template = template(profileNode, args); - template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args); - } else if (profileNode instanceof ProfileInvokeNode) { - ProfileInvokeNode profileInvokeNode = (ProfileInvokeNode) profileNode; - // Method invocation event - Arguments args = new Arguments(profileMethodEntryWithProbability, graph.getGuardsStage(), tool.getLoweringStage()); - - args.add("counters", counters); - args.add("random", profileInvokeNode.getRandom()); - args.add("step", step); - args.add("stepLog", stepLog); - args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog()); - args.addConst("probLog", profileInvokeNode.getProbabilityLog()); - SnippetTemplate template = template(profileNode, args); - template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args); - } else { - throw new GraalError("Unsupported profile node type: " + profileNode); - } - - assert profileNode.hasNoUsages(); - if (!profileNode.isDeleted()) { - GraphUtil.killWithUnusedFloatingInputs(profileNode); - } - } - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProfileSnippets.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProfileSnippets.java deleted file mode 100644 index 3a5ad282d3ac..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProfileSnippets.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.replacements.profiling; - -import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.backedgeCounterOffset; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.invocationCounterIncrement; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.invocationCounterOffset; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.invocationCounterShift; -import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY; -import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; -import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; - -import org.graalvm.compiler.api.replacements.Snippet; -import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; -import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; -import org.graalvm.compiler.debug.DebugHandlersFactory; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.graph.Node.ConstantNodeParameter; -import org.graalvm.compiler.graph.Node.NodeIntrinsic; -import org.graalvm.compiler.hotspot.HotSpotBackend; -import org.graalvm.compiler.hotspot.meta.HotSpotProviders; -import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode; -import org.graalvm.compiler.hotspot.nodes.profiling.ProfileBranchNode; -import org.graalvm.compiler.hotspot.nodes.profiling.ProfileInvokeNode; -import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode; -import org.graalvm.compiler.hotspot.word.MethodCountersPointer; -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.NamedLocationIdentity; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.extended.ForeignCallNode; -import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.replacements.SnippetTemplate; -import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates; -import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; -import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; -import org.graalvm.compiler.replacements.Snippets; - -import jdk.vm.ci.code.CodeUtil; -import jdk.vm.ci.code.TargetDescription; -import org.graalvm.word.LocationIdentity; - -public class ProfileSnippets implements Snippets { - public static final LocationIdentity METHOD_COUNTERS = NamedLocationIdentity.mutable("MethodCounters"); - - @NodeIntrinsic(ForeignCallNode.class) - public static native void methodInvocationEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters); - - @Snippet - protected static int notificationMask(int freqLog, int stepLog) { - int stepMask = (1 << stepLog) - 1; - int frequencyMask = (1 << freqLog) - 1; - return frequencyMask & ~stepMask; - } - - @Snippet - public static void profileMethodEntry(MethodCountersPointer counters, int step, int stepLog, @ConstantParameter int freqLog) { - int counterValue = counters.readInt(invocationCounterOffset(INJECTED_VMCONFIG), METHOD_COUNTERS) + invocationCounterIncrement(INJECTED_VMCONFIG) * step; - counters.writeIntSideEffectFree(invocationCounterOffset(INJECTED_VMCONFIG), counterValue, METHOD_COUNTERS); - if (freqLog >= 0) { - final int mask = notificationMask(freqLog, stepLog); - if (probability(SLOW_PATH_PROBABILITY, (counterValue & (mask << invocationCounterShift(INJECTED_VMCONFIG))) == 0)) { - methodInvocationEvent(HotSpotBackend.INVOCATION_EVENT, counters); - } - } - } - - @NodeIntrinsic(ForeignCallNode.class) - public static native void methodBackedgeEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters, int bci, int targetBci); - - @Snippet - public static void profileBackedge(MethodCountersPointer counters, int step, int stepLog, @ConstantParameter int freqLog, int bci, int targetBci) { - int counterValue = counters.readInt(backedgeCounterOffset(INJECTED_VMCONFIG), METHOD_COUNTERS) + invocationCounterIncrement(INJECTED_VMCONFIG) * step; - counters.writeIntSideEffectFree(backedgeCounterOffset(INJECTED_VMCONFIG), counterValue, METHOD_COUNTERS); - final int mask = notificationMask(freqLog, stepLog); - if (probability(SLOW_PATH_PROBABILITY, (counterValue & (mask << invocationCounterShift(INJECTED_VMCONFIG))) == 0)) { - methodBackedgeEvent(HotSpotBackend.BACKEDGE_EVENT, counters, bci, targetBci); - } - } - - @Snippet - public static void profileConditionalBackedge(MethodCountersPointer counters, int step, int stepLog, @ConstantParameter int freqLog, boolean branchCondition, int bci, int targetBci) { - if (branchCondition) { - profileBackedge(counters, step, stepLog, freqLog, bci, targetBci); - } - } - - public static class Templates extends AbstractTemplates { - private final SnippetInfo profileMethodEntry = snippet(ProfileSnippets.class, "profileMethodEntry"); - private final SnippetInfo profileBackedge = snippet(ProfileSnippets.class, "profileBackedge"); - private final SnippetInfo profileConditionalBackedge = snippet(ProfileSnippets.class, "profileConditionalBackedge"); - - public Templates(OptionValues options, Iterable factories, HotSpotProviders providers, TargetDescription target) { - super(options, factories, providers, providers.getSnippetReflection(), target); - } - - public void lower(ProfileNode profileNode, LoweringTool tool) { - StructuredGraph graph = profileNode.graph(); - LoadMethodCountersNode counters = graph.unique(new LoadMethodCountersNode(profileNode.getProfiledMethod())); - ConstantNode step = ConstantNode.forInt(profileNode.getStep(), graph); - ConstantNode stepLog = ConstantNode.forInt(CodeUtil.log2(profileNode.getStep()), graph); - - if (profileNode instanceof ProfileBranchNode) { - // Backedge event - ProfileBranchNode profileBranchNode = (ProfileBranchNode) profileNode; - SnippetInfo snippet = profileBranchNode.hasCondition() ? profileConditionalBackedge : profileBackedge; - Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); - ConstantNode bci = ConstantNode.forInt(profileBranchNode.bci(), graph); - ConstantNode targetBci = ConstantNode.forInt(profileBranchNode.targetBci(), graph); - args.add("counters", counters); - args.add("step", step); - args.add("stepLog", stepLog); - args.addConst("freqLog", profileBranchNode.getNotificationFreqLog()); - if (profileBranchNode.hasCondition()) { - args.add("branchCondition", profileBranchNode.branchCondition()); - } - args.add("bci", bci); - args.add("targetBci", targetBci); - - SnippetTemplate template = template(profileNode, args); - template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args); - } else if (profileNode instanceof ProfileInvokeNode) { - ProfileInvokeNode profileInvokeNode = (ProfileInvokeNode) profileNode; - // Method invocation event - Arguments args = new Arguments(profileMethodEntry, graph.getGuardsStage(), tool.getLoweringStage()); - args.add("counters", counters); - args.add("step", step); - args.add("stepLog", stepLog); - args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog()); - SnippetTemplate template = template(profileNode, args); - template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args); - } else { - throw new GraalError("Unsupported profile node type: " + profileNode); - } - - assert profileNode.hasNoUsages(); - if (!profileNode.isDeleted()) { - GraphUtil.killWithUnusedFloatingInputs(profileNode); - } - } - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallSnippets.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallSnippets.java index a094ee5f5890..b1446eedad72 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallSnippets.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallSnippets.java @@ -38,7 +38,7 @@ import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; import org.graalvm.compiler.hotspot.nodes.DeoptimizeCallerNode; -import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode; +import org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil; import org.graalvm.compiler.hotspot.word.KlassPointer; import org.graalvm.compiler.nodes.NamedLocationIdentity; import org.graalvm.compiler.nodes.PiNode; @@ -87,15 +87,15 @@ public static void handlePendingException(Word thread, boolean shouldClearExcept */ @Snippet public static Object verifyObject(Object object) { - if (GraalHotSpotVMConfigNode.verifyOops()) { - Word verifyOopCounter = WordFactory.unsigned(GraalHotSpotVMConfigNode.verifyOopCounterAddress()); + if (HotSpotReplacementsUtil.verifyOops(INJECTED_VMCONFIG)) { + Word verifyOopCounter = WordFactory.unsigned(HotSpotReplacementsUtil.verifyOopCounterAddress(INJECTED_VMCONFIG)); verifyOopCounter.writeInt(0, verifyOopCounter.readInt(0) + 1); Pointer oop = Word.objectToTrackedPointer(object); if (object != null) { GuardingNode anchorNode = SnippetAnchorNode.anchor(); // make sure object is 'reasonable' - if (!oop.and(WordFactory.unsigned(GraalHotSpotVMConfigNode.verifyOopMask())).equal(WordFactory.unsigned(GraalHotSpotVMConfigNode.verifyOopBits()))) { + if (!oop.and(WordFactory.unsigned(HotSpotReplacementsUtil.verifyOopMask(INJECTED_VMCONFIG))).equal(WordFactory.unsigned(HotSpotReplacementsUtil.verifyOopBits(INJECTED_VMCONFIG)))) { fatal("oop not in heap: %p", oop.rawValue()); } diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NegativeArraySizeExceptionStub.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NegativeArraySizeExceptionStub.java new file mode 100644 index 000000000000..17f1379f1bfb --- /dev/null +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NegativeArraySizeExceptionStub.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.stubs; + +import static org.graalvm.compiler.hotspot.stubs.StubUtil.printNumber; + +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.nodes.AllocaNode; +import org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil; +import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.serviceprovider.JavaVersionUtil; +import org.graalvm.compiler.word.Word; + +import jdk.vm.ci.code.Register; + +/** + * Stub to allocate a {@link NegativeArraySizeException} thrown by a bytecode when the length of an + * array allocation is negative. + */ +public class NegativeArraySizeExceptionStub extends CreateExceptionStub { + public NegativeArraySizeExceptionStub(OptionValues options, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { + super("createNegativeArraySizeException", options, providers, linkage); + } + + private static final boolean PRINT_LENGTH_IN_EXCEPTION = JavaVersionUtil.JAVA_SPEC >= 11; + + @Override + protected Object getConstantParameterValue(int index, String name) { + switch (index) { + case 1: + return providers.getRegisters().getThreadRegister(); + case 2: + // required bytes for maximum length + nullbyte + return OutOfBoundsExceptionStub.MAX_INT_STRING_SIZE + 1; + case 3: + return PRINT_LENGTH_IN_EXCEPTION; + default: + throw GraalError.shouldNotReachHere("unknown parameter " + name + " at index " + index); + } + } + + @Snippet + private static Object createNegativeArraySizeException(int length, @ConstantParameter Register threadRegister, @ConstantParameter int bufferSizeInBytes, + @ConstantParameter boolean printLengthInException) { + if (printLengthInException) { + Word buffer = AllocaNode.alloca(bufferSizeInBytes, HotSpotReplacementsUtil.wordSize()); + Word ptr = printNumber(buffer, length); + ptr.writeByte(0, (byte) 0); + return createException(threadRegister, NegativeArraySizeException.class, buffer); + } else { + return createException(threadRegister, NegativeArraySizeException.class); + } + } +} diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/OutOfBoundsExceptionStub.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/OutOfBoundsExceptionStub.java index 905809cfe0a0..26fcaad151a0 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/OutOfBoundsExceptionStub.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/OutOfBoundsExceptionStub.java @@ -50,7 +50,7 @@ public OutOfBoundsExceptionStub(OptionValues options, HotSpotProviders providers // JDK-8201593: Print array length in ArrayIndexOutOfBoundsException. private static final boolean PRINT_LENGTH_IN_EXCEPTION = JavaVersionUtil.JAVA_SPEC >= 11; - private static final int MAX_INT_STRING_SIZE = Integer.toString(Integer.MIN_VALUE).length(); + static final int MAX_INT_STRING_SIZE = Integer.toString(Integer.MIN_VALUE).length(); private static final String STR_INDEX = "Index "; private static final String STR_OUTOFBOUNDSFORLENGTH = " out of bounds for length "; diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java index d7aa77d32cb0..289f6a4a250b 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java @@ -25,7 +25,6 @@ package org.graalvm.compiler.hotspot.stubs; import static org.graalvm.compiler.core.GraalCompiler.emitFrontEnd; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure; import static org.graalvm.compiler.debug.DebugOptions.DebugStubsAndSnippets; import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPT_BLOB_UNCOMMON_TRAP; @@ -198,8 +197,6 @@ public synchronized InstalledCode getCode(final Backend backend) { try (DebugContext.Scope s = debug.scope("CodeInstall", compResult); DebugContext.Activation a = debug.activate()) { assert destroyedCallerRegisters != null; - // Add a GeneratePIC check here later, we don't want to install - // code if we don't have a corresponding VM global symbol. HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, null, null, compResult, options); code = codeCache.installCode(null, compiledCode, null, null, false); } catch (Throwable e) { @@ -219,7 +216,7 @@ public synchronized InstalledCode getCode(final Backend backend) { private CompilationResult buildCompilationResult(DebugContext debug, final Backend backend) { CompilationIdentifier compilationId = getStubCompilationId(); final StructuredGraph graph = getGraph(debug, compilationId); - CompilationResult compResult = new CompilationResult(compilationId, toString(), GeneratePIC.getValue(options)); + CompilationResult compResult = new CompilationResult(compilationId, toString()); // Stubs cannot be recompiled so they cannot be compiled with assumptions assert graph.getAssumptions() == null; diff --git a/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java b/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java index ef93c22ae97f..b3802f7b7b50 100644 --- a/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java +++ b/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java @@ -243,7 +243,6 @@ import static org.graalvm.compiler.bytecode.Bytecodes.TABLESWITCH; import static org.graalvm.compiler.bytecode.Bytecodes.nameOf; import static org.graalvm.compiler.core.common.GraalOptions.DeoptALot; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.core.common.GraalOptions.HotSpotPrintInlining; import static org.graalvm.compiler.core.common.GraalOptions.PrintProfilingInformation; import static org.graalvm.compiler.core.common.GraalOptions.StressExplicitExceptionCode; @@ -350,6 +349,7 @@ import org.graalvm.compiler.nodes.ParameterNode; import org.graalvm.compiler.nodes.PiNode; import org.graalvm.compiler.nodes.PluginReplacementNode; +import org.graalvm.compiler.nodes.PluginReplacementWithExceptionNode; import org.graalvm.compiler.nodes.ProfileData.BranchProbabilityData; import org.graalvm.compiler.nodes.ProfileData.ProfileSource; import org.graalvm.compiler.nodes.ProfileData.SwitchProbabilityData; @@ -408,10 +408,9 @@ import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo; import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPluginContext; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver; -import org.graalvm.compiler.nodes.graphbuilderconf.InvokeDynamicPlugin; import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin; -import org.graalvm.compiler.nodes.graphbuilderconf.ProfilingPlugin; import org.graalvm.compiler.nodes.java.ArrayLengthNode; import org.graalvm.compiler.nodes.java.ExceptionObjectNode; import org.graalvm.compiler.nodes.java.FinalFieldBarrierNode; @@ -496,7 +495,11 @@ public class BytecodeParser extends CoreProvidersDelegate implements GraphBuilde private boolean bciCanBeDuplicated = false; @Override - public FrameState getIntrinsicReturnState(JavaKind returnKind, ValueNode returnVal) { + public FrameState getInvocationPluginReturnState(JavaKind returnKind, ValueNode returnVal) { + if (parsingIntrinsic()) { + // Invocation plugins inside of snippets shouldn't produce a real FrameState + return graph.add(new FrameState(BytecodeFrame.AFTER_BCI)); + } FrameStateBuilder frameStateBuilder = frameState; if (returnVal != null) { // Push the return value on the top of stack @@ -512,6 +515,14 @@ public FrameState getIntrinsicReturnState(JavaKind returnKind, ValueNode returnV } } + @Override + public FrameState getInvocationPluginBeforeState() { + assert isParsingInvocationPlugin(); + ResolvedJavaMethod callee = invocationPluginContext.targetMethod; + JavaKind[] argSlotKinds = callee.getSignature().toParameterKinds(!callee.isStatic()); + return frameState.create(bci(), getNonIntrinsicAncestor(), false, argSlotKinds, invocationPluginContext.args); + } + @Override public boolean canMergeIntrinsicReturns() { return true; @@ -1031,7 +1042,6 @@ protected void buildRootMethod() { } cleanupFinalGraph(); - ComputeLoopFrequenciesClosure.compute(graph); } protected BciBlockMapping generateBlockMap() { @@ -1123,12 +1133,6 @@ protected void build(FixedWithNextNode startInstruction, FrameStateBuilder start genMonitorEnter(methodSynchronizedObject, bci()); } - ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin(); - if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { - FrameState stateBefore = createCurrentFrameState(); - profilingPlugin.profileInvoke(this, method, stateBefore); - } - genInfoPointNode(InfopointReason.METHOD_START, null); } @@ -1488,12 +1492,6 @@ protected ValueNode genZeroExtend(ValueNode input, int bitCount) { } protected void genGoto() { - ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin(); - if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { - FrameState stateBefore = createCurrentFrameState(); - int targetBci = currentBlock.getSuccessor(0).startBci; - profilingPlugin.profileGoto(this, method, bci(), targetBci, stateBefore); - } appendGoto(currentBlock.getSuccessor(0)); assert currentBlock.numNormalSuccessors() == 1; } @@ -1743,40 +1741,14 @@ protected void genInvokeVirtual(ResolvedJavaMethod resolvedTarget) { private boolean genDynamicInvokeHelper(ResolvedJavaMethod target, int cpi, int opcode) { assert opcode == INVOKEDYNAMIC || opcode == INVOKEVIRTUAL; - InvokeDynamicPlugin invokeDynamicPlugin = graphBuilderConfig.getPlugins().getInvokeDynamicPlugin(); - - if (opcode == INVOKEVIRTUAL && invokeDynamicPlugin != null && !invokeDynamicPlugin.isResolvedDynamicInvoke(this, cpi, opcode)) { - // regular invokevirtual, let caller handle it - return false; - } - - if (GeneratePIC.getValue(options) && (invokeDynamicPlugin == null || !invokeDynamicPlugin.supportsDynamicInvoke(this, cpi, opcode))) { - // bail out if static compiler and no dynamic type support - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); - return true; - } - JavaConstant appendix = constantPool.lookupAppendix(cpi, opcode); ValueNode appendixNode = null; if (appendix != null) { - if (invokeDynamicPlugin != null) { - invokeDynamicPlugin.recordDynamicMethod(this, cpi, opcode, target); - - // Will perform runtime type checks and static initialization - FrameState stateBefore = createCurrentFrameState(); - appendixNode = invokeDynamicPlugin.genAppendixNode(this, cpi, opcode, appendix, stateBefore); - } else { - appendixNode = ConstantNode.forConstant(appendix, getMetaAccess(), graph); - } + appendixNode = ConstantNode.forConstant(appendix, getMetaAccess(), graph); frameState.push(JavaKind.Object, appendixNode); - } else if (GeneratePIC.getValue(options)) { - // Need to emit runtime guard and perform static initialization. - // Not implemented yet. - append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); - return true; } boolean hasReceiver = (opcode == INVOKEDYNAMIC) ? false : !target.isStatic(); @@ -1831,6 +1803,8 @@ static class CurrentInvoke { protected final ConstantPool constantPool; protected final IntrinsicContext intrinsicContext; + protected InvocationPluginContext invocationPluginContext; + @Override public InvokeKind getInvokeKind() { return currentInvoke == null ? null : currentInvoke.kind; @@ -2198,6 +2172,23 @@ public void replacePlugin(GeneratedInvocationPlugin plugin, ResolvedJavaMethod t } } + @Override + public void replacePluginWithException(GeneratedInvocationPlugin plugin, ResolvedJavaMethod targetMethod, ValueNode[] args, + PluginReplacementWithExceptionNode.ReplacementWithExceptionFunction replacementFunction) { + assert replacementFunction != null; + JavaType returnType = maybeEagerlyResolve(targetMethod.getSignature().getReturnType(method.getDeclaringClass()), targetMethod.getDeclaringClass()); + StampPair returnStamp = getReplacements().getGraphBuilderPlugins().getOverridingStamp(this, returnType, false); + if (returnStamp == null) { + returnStamp = StampFactory.forDeclaredType(getAssumptions(), returnType, false); + } + WithExceptionNode node = new PluginReplacementWithExceptionNode(returnStamp.getTrustedStamp(), args, replacementFunction, plugin.getClass().getSimpleName()); + if (returnType.getJavaKind() == JavaKind.Void) { + add(node); + } else { + addPush(returnType.getJavaKind(), node); + } + } + protected boolean tryInvocationPlugin(InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType) { InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod, true); if (plugin != null) { @@ -2214,13 +2205,58 @@ protected boolean tryInvocationPlugin(InvokeKind invokeKind, ValueNode[] args, R return false; } + class InvocationPluginScope implements DebugCloseable { + InvocationPluginScope(InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, InvocationPlugin plugin) { + assert invocationPluginContext == null; + invocationPluginContext = new InvocationPluginContext(invokeKind, args, targetMethod, resultType, plugin); + } + + @Override + public void close() { + invocationPluginContext = null; + } + } + + @Override + public Invoke invokeFallback(FixedWithNextNode predecessor, EndNode end) { + assert isParsingInvocationPlugin(); + assert currentInvoke != null : "must be processing invoke"; + + FixedWithNextNode previousLastInstr = lastInstr; + lastInstr = predecessor; + InvokeKind invokeKind = invocationPluginContext.invokeKind; + ResolvedJavaMethod targetMethod = invocationPluginContext.targetMethod; + ValueNode[] args = invocationPluginContext.args; + int invokeBci = bci(); + JavaTypeProfile profile = getProfileForInvoke(invokeKind); + // inlineInfo is null during application + ExceptionEdgeAction edgeAction = getActionForInvokeExceptionEdge(null); + + int beforeDepth = getFrameStateBuilder().stackSize(); + Invoke invoke = createNonInlinedInvoke(edgeAction, invokeBci, args, targetMethod, invokeKind, currentInvoke.returnType.getJavaKind(), currentInvoke.returnType, profile); + if (getFrameStateBuilder().stackSize() != beforeDepth) { + assert getFrameStateBuilder().stackSize() > beforeDepth : "only pushes expected"; + getFrameStateBuilder().pop(currentInvoke.returnType.getJavaKind()); + } + graph.getInliningLog().addDecision(invoke, false, "GraphBuilderPhase", null, null, "bytecode parser did not replace invoke"); + invoke.setInlineControl(Invoke.InlineControl.BytecodesOnly); + lastInstr.setNext(end); + lastInstr = previousLastInstr; + return invoke; + } + + @Override + public boolean isParsingInvocationPlugin() { + return invocationPluginContext != null; + } + @SuppressWarnings("try") protected boolean applyInvocationPlugin(InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, InvocationPlugin plugin) { InvocationPluginReceiver pluginReceiver = invocationPluginReceiver.init(targetMethod, args); assert invokeKind.isDirect() : "Cannot apply invocation plugin on an indirect call site."; InvocationPluginAssertions assertions = Assertions.assertionsEnabled() ? new InvocationPluginAssertions(plugin, args, targetMethod, resultType) : null; - try (DebugCloseable context = openNodeContext(targetMethod)) { + try (DebugCloseable context = openNodeContext(targetMethod); InvocationPluginScope pluginScope = new InvocationPluginScope(invokeKind, args, targetMethod, resultType, plugin)) { Mark mark = graph.getMark(); if (plugin.execute(this, targetMethod, pluginReceiver, args)) { checkDeoptAfterPlugin(mark, targetMethod); @@ -2240,7 +2276,7 @@ private boolean checkDeoptAfterPlugin(Mark mark, ResolvedJavaMethod targetMethod if (!needsExplicitException()) { return true; } - if (StrictDeoptInsertionChecks.getValue(getOptions()) || (Assertions.assertionsEnabled() && disallowDeoptInPlugins())) { + if (StrictDeoptInsertionChecks.getValue(getOptions()) || (Assertions.assertionsEnabled() && !allowDeoptInPlugins())) { for (Node node : graph.getNewNodes(mark)) { if (node instanceof FixedGuardNode || node instanceof DeoptimizeNode) { throw new AssertionError("node " + node + " may not be used by plugin in graphs with explicit exceptions for " + targetMethod); @@ -3673,11 +3709,6 @@ protected void genIf(LogicNode conditionInput, BciBlock trueBlockInput, BciBlock BciBlock falseBlock = falseBlockInput; LogicNode condition = conditionInput; BranchProbabilityData profileData = originalProfileData; - FrameState stateBefore = null; - ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin(); - if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { - stateBefore = createCurrentFrameState(); - } // Remove a logic negation node. if (condition instanceof LogicNegationNode) { @@ -3715,9 +3746,6 @@ protected void genIf(LogicNode conditionInput, BciBlock trueBlockInput, BciBlock } boolean negated = deoptBlock == trueBlock; if (!isPotentialCountedLoopExit(condition, deoptBlock)) { - if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { - profilingPlugin.profileGoto(this, method, bci(), noDeoptBlock.startBci, stateBefore); - } append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, negated, survivingSuccessorPosition)); appendGoto(noDeoptBlock); } else { @@ -3739,10 +3767,6 @@ protected void genIf(LogicNode conditionInput, BciBlock trueBlockInput, BciBlock return; } - if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { - profilingPlugin.profileIf(this, method, bci(), condition, trueBlock.startBci, falseBlock.startBci, stateBefore); - } - int oldBci = stream.currentBCI(); int trueBlockInt = checkPositiveIntConstantPushed(trueBlock); if (trueBlockInt != -1) { @@ -3863,19 +3887,9 @@ private void genConstantTargetIf(BciBlock trueBlock, BciBlock falseBlock, LogicN if (targetAtStart == Bytecodes.GOTO && nextBlock.getPredecessorCount() == 1) { // This is an empty block. Skip it. BciBlock successorBlock = nextBlock.successors.get(0); - ProfilingPlugin profilingPlugin = graphBuilderConfig.getPlugins().getProfilingPlugin(); - if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { - FrameState stateBefore = createCurrentFrameState(); - profilingPlugin.profileGoto(this, method, bci(), successorBlock.startBci, stateBefore); - } appendGoto(successorBlock); assert nextBlock.numNormalSuccessors() == 1; } else { - ProfilingPlugin profilingPlugin = graphBuilderConfig.getPlugins().getProfilingPlugin(); - if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { - FrameState stateBefore = createCurrentFrameState(); - profilingPlugin.profileGoto(this, method, bci(), nextBlock.startBci, stateBefore); - } appendGoto(nextBlock); } } @@ -4690,7 +4704,7 @@ private static Class arrayTypeCodeToClass(int code) { private void genNewPrimitiveArray(int typeCode) { ResolvedJavaType elementType = getMetaAccess().lookupJavaType(arrayTypeCodeToClass(typeCode)); - ValueNode length = frameState.pop(JavaKind.Int); + ValueNode length = maybeEmitExplicitNegativeArraySizeCheck(frameState.pop(JavaKind.Int)); for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { if (plugin.handleNewArray(this, elementType, length)) { @@ -4703,14 +4717,10 @@ private void genNewPrimitiveArray(int typeCode) { private void genNewObjectArray(int cpi) { JavaType type = lookupType(cpi, ANEWARRAY); - genNewObjectArray(type); - } - - private void genNewObjectArray(JavaType type) { if (typeIsResolved(type)) { genNewObjectArray((ResolvedJavaType) type); } else { - ValueNode length = frameState.pop(JavaKind.Int); + ValueNode length = maybeEmitExplicitNegativeArraySizeCheck(frameState.pop(JavaKind.Int)); handleUnresolvedNewObjectArray(type, length); } } @@ -4722,7 +4732,7 @@ private void genNewObjectArray(ResolvedJavaType resolvedType) { classInitializationPlugin.apply(this, resolvedType.getArrayClass(), this::createCurrentFrameState); } - ValueNode length = frameState.pop(JavaKind.Int); + ValueNode length = maybeEmitExplicitNegativeArraySizeCheck(frameState.pop(JavaKind.Int)); for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { if (plugin.handleNewArray(this, resolvedType, length)) { return; @@ -4736,15 +4746,11 @@ private void genNewMultiArray(int cpi) { JavaType type = lookupType(cpi, MULTIANEWARRAY); int rank = getStream().readUByte(bci() + 3); ValueNode[] dims = new ValueNode[rank]; - genNewMultiArray(type, rank, dims); - } - - private void genNewMultiArray(JavaType type, int rank, ValueNode[] dims) { if (typeIsResolved(type)) { genNewMultiArray((ResolvedJavaType) type, rank, dims); } else { for (int i = rank - 1; i >= 0; i--) { - dims[i] = frameState.pop(JavaKind.Int); + dims[i] = maybeEmitExplicitNegativeArraySizeCheck(frameState.pop(JavaKind.Int)); } handleUnresolvedNewMultiArray(type, dims); } @@ -4758,7 +4764,7 @@ private void genNewMultiArray(ResolvedJavaType resolvedType, int rank, ValueNode } for (int i = rank - 1; i >= 0; i--) { - dims[i] = frameState.pop(JavaKind.Int); + dims[i] = maybeEmitExplicitNegativeArraySizeCheck(frameState.pop(JavaKind.Int)); } for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { @@ -4790,10 +4796,6 @@ private void genGetField(JavaField field, ValueNode receiverInput) { } private void genGetField(ResolvedJavaField resolvedField, ValueNode receiver) { - if (!parsingIntrinsic() && GeneratePIC.getValue(getOptions())) { - graph.recordField(resolvedField); - } - for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { if (plugin.handleLoadField(this, receiver, resolvedField)) { return; @@ -4887,10 +4889,6 @@ private void genPutField(JavaField field, ValueNode value) { ValueNode receiver = maybeEmitExplicitNullCheck(receiverInput); ResolvedJavaField resolvedField = (ResolvedJavaField) field; - if (!parsingIntrinsic() && GeneratePIC.getValue(getOptions())) { - graph.recordField(resolvedField); - } - for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { if (plugin.handleStoreField(this, receiver, resolvedField, value)) { return; @@ -4917,10 +4915,6 @@ private void genGetStatic(JavaField field) { return; } - if (!parsingIntrinsic() && GeneratePIC.getValue(getOptions())) { - graph.recordField(resolvedField); - } - /* * Javac does not allow use of "$assertionsDisabled" for a field name but Eclipse does, in * which case a suffix is added to the generated field. @@ -5011,10 +5005,6 @@ protected void genPutStatic(JavaField field) { return; } - if (!parsingIntrinsic() && GeneratePIC.getValue(getOptions())) { - graph.recordField(resolvedField); - } - ClassInitializationPlugin classInitializationPlugin = this.graphBuilderConfig.getPlugins().getClassInitializationPlugin(); ResolvedJavaType holder = resolvedField.getDeclaringClass(); if (classInitializationPlugin != null) { diff --git a/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java b/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java deleted file mode 100644 index 3771cdf022a1..000000000000 --- a/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.java; - -import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyRelativeFrequencies; - -import java.util.List; - -import org.graalvm.collections.EconomicMap; -import org.graalvm.compiler.nodes.AbstractBeginNode; -import org.graalvm.compiler.nodes.AbstractMergeNode; -import org.graalvm.compiler.nodes.ControlSplitNode; -import org.graalvm.compiler.nodes.FixedNode; -import org.graalvm.compiler.nodes.LoopBeginNode; -import org.graalvm.compiler.nodes.LoopExitNode; -import org.graalvm.compiler.nodes.ProfileData.BranchProbabilityData; -import org.graalvm.compiler.nodes.ProfileData.LoopFrequencyData; -import org.graalvm.compiler.nodes.ProfileData.ProfileSource; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; -import org.graalvm.compiler.phases.Phase; -import org.graalvm.compiler.phases.graph.ReentrantNodeIterator; - -public final class ComputeLoopFrequenciesClosure extends ReentrantNodeIterator.NodeIteratorClosure { - - private static final ComputeLoopFrequenciesClosure INSTANCE = new ComputeLoopFrequenciesClosure(); - - private static final BranchProbabilityData ZERO = BranchProbabilityData.create(0.0, ProfileSource.UNKNOWN); - private static final BranchProbabilityData ONE = BranchProbabilityData.create(1.0, ProfileSource.UNKNOWN); - - private ComputeLoopFrequenciesClosure() { - // nothing to do - } - - private static BranchProbabilityData add(BranchProbabilityData x, BranchProbabilityData y) { - double p = x.getDesignatedSuccessorProbability() + y.getDesignatedSuccessorProbability(); - return BranchProbabilityData.create(p, x.getProfileSource().combine(y.getProfileSource())); - } - - private static BranchProbabilityData scale(BranchProbabilityData x, double scaleFactor) { - return scaleAndCombine(x, scaleFactor, x.getProfileSource()); - } - - private static BranchProbabilityData scaleAndCombine(BranchProbabilityData x, double scaleFactor, ProfileSource otherSource) { - double p = multiplyRelativeFrequencies(x.getDesignatedSuccessorProbability(), scaleFactor); - return BranchProbabilityData.create(p, x.getProfileSource().combine(otherSource)); - } - - @Override - protected BranchProbabilityData processNode(FixedNode node, BranchProbabilityData currentState) { - // normal nodes never change the probability of a path - return currentState; - } - - @Override - protected BranchProbabilityData merge(AbstractMergeNode merge, List states) { - // a merge has the sum of all predecessor probabilities - BranchProbabilityData result = ZERO; - for (BranchProbabilityData s : states) { - result = add(result, s); - } - return result; - } - - @Override - protected BranchProbabilityData afterSplit(AbstractBeginNode node, BranchProbabilityData oldState) { - // a control split splits up the probability - ControlSplitNode split = (ControlSplitNode) node.predecessor(); - return scaleAndCombine(oldState, split.probability(node), split.getProfileData().getProfileSource()); - } - - @Override - protected EconomicMap processLoop(LoopBeginNode loop, BranchProbabilityData initialState) { - EconomicMap exitStates = ReentrantNodeIterator.processLoop(this, loop, ONE).exitStates; - - BranchProbabilityData exitState = ZERO; - for (BranchProbabilityData e : exitStates.getValues()) { - exitState = add(exitState, e); - } - double exitRelativeFrequency = exitState.getDesignatedSuccessorProbability(); - exitRelativeFrequency = Math.min(1.0, exitRelativeFrequency); - exitRelativeFrequency = Math.max(ControlFlowGraph.MIN_RELATIVE_FREQUENCY, exitRelativeFrequency); - double loopFrequency = 1.0 / exitRelativeFrequency; - loop.setLoopFrequency(LoopFrequencyData.create(loopFrequency, exitState.getProfileSource())); - - double adjustmentFactor = initialState.getDesignatedSuccessorProbability() * loopFrequency; - exitStates.replaceAll((exitNode, state) -> scale(state, adjustmentFactor)); - - return exitStates; - } - - /** - * Computes the frequencies of all loops in the given graph. This is done by performing a - * reverse postorder iteration and computing the probability of all fixed nodes. The combined - * probability of all exits of a loop can be used to compute the loop's expected frequency. - */ - public static void compute(StructuredGraph graph) { - if (graph.hasLoops()) { - ReentrantNodeIterator.apply(INSTANCE, graph.start(), ONE); - } - } - - public static class ComputeLoopFrequencyPhase extends Phase { - - @Override - protected void run(StructuredGraph graph) { - compute(graph); - } - } - - public static final ComputeLoopFrequencyPhase PHASE_INSTANCE = new ComputeLoopFrequencyPhase(); - -} diff --git a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticOp.java b/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticOp.java index 349f3f3b7a33..d3b60cf23865 100644 --- a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticOp.java +++ b/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticOp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Call.java b/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Call.java index 087e3325af2d..3097dd8baa0f 100644 --- a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Call.java +++ b/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Call.java @@ -27,7 +27,6 @@ import static jdk.vm.ci.code.ValueUtil.asRegister; import static jdk.vm.ci.code.ValueUtil.isRegister; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; @@ -208,19 +207,15 @@ public static void directCall(CompilationResultBuilder crb, AArch64MacroAssemble public static void directCall(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget callTarget, Register scratch, LIRFrameState info, Label label) { int before = masm.position(); if (scratch != null) { - if (GeneratePIC.getValue(crb.getOptions())) { - masm.bl(0); - } else { - /* - * Offset might not fit into a 28-bit immediate, generate an indirect call with a - * 64-bit immediate address which is fixed up by HotSpot. - */ - masm.movNativeAddress(scratch, 0L, true); - masm.blr(scratch); - } + /* + * Offset might not fit into a 28-bit immediate, generate an indirect call with a 64-bit + * immediate address which is fixed up by HotSpot. + */ + masm.movNativeAddress(scratch, 0L, true); + masm.blr(scratch); } else { - // Address is fixed up by HotSpot. - masm.bl(0); + // Address is fixed up by the runtime. + masm.bl(); } if (label != null) { // We need this label to be the return address. @@ -244,12 +239,8 @@ public static void indirectCall(CompilationResultBuilder crb, AArch64MacroAssemb public static void directJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget callTarget) { try (AArch64MacroAssembler.ScratchRegister scratch = masm.getScratchRegister()) { int before = masm.position(); - if (GeneratePIC.getValue(crb.getOptions())) { - masm.jmp(); - } else { - masm.movNativeAddress(scratch.getRegister(), 0L); - masm.jmp(scratch.getRegister()); - } + masm.movNativeAddress(scratch.getRegister(), 0L); + masm.jmp(scratch.getRegister()); int after = masm.position(); crb.recordDirectCall(before, after, callTarget, null); masm.ensureUniquePC(); diff --git a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ControlFlow.java b/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ControlFlow.java index 105d18685613..ededa35602f3 100644 --- a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ControlFlow.java +++ b/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ControlFlow.java @@ -40,6 +40,7 @@ import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.ScratchRegister; import org.graalvm.compiler.code.CompilationResult.JumpTable; +import org.graalvm.compiler.code.CompilationResult.JumpTable.EntryFormat; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.debug.GraalError; @@ -370,7 +371,7 @@ private static void emitCompareHelper(CompilationResultBuilder crb, AArch64Macro } else { try (ScratchRegister scratch = masm.getScratchRegister()) { Register scratchReg = scratch.getRegister(); - AArch64Move.const2reg(crb, masm, scratchReg, jc); + AArch64Move.const2reg((AArch64Kind) key.getPlatformKind(), crb, masm, scratchReg, jc); masm.cmp(cmpSize, asRegister(key), scratchReg); } } @@ -443,7 +444,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { for (LabelRef target : targets) { masm.jmp(target.label()); } - JumpTable jt = new JumpTable(jumpTable.position(), lowKey, highKey, 4); + JumpTable jt = new JumpTable(jumpTable.position(), lowKey, highKey, EntryFormat.OFFSET); crb.compilationResult.addAnnotation(jt); } } diff --git a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java b/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java index f2c3165df520..e75a5e0b09c5 100755 --- a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java +++ b/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java @@ -28,12 +28,10 @@ import static jdk.vm.ci.aarch64.AArch64.SIMD; import static jdk.vm.ci.aarch64.AArch64.sp; import static jdk.vm.ci.aarch64.AArch64.zr; -import static jdk.vm.ci.code.ValueUtil.asAllocatableValue; import static jdk.vm.ci.code.ValueUtil.asRegister; import static jdk.vm.ci.code.ValueUtil.asStackSlot; import static jdk.vm.ci.code.ValueUtil.isRegister; import static jdk.vm.ci.code.ValueUtil.isStackSlot; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; @@ -64,7 +62,6 @@ import org.graalvm.compiler.lir.StandardOp.ValueMoveOp; import org.graalvm.compiler.lir.VirtualStackSlot; import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.options.OptionValues; import jdk.vm.ci.aarch64.AArch64Kind; import jdk.vm.ci.code.MemoryBarriers; @@ -73,7 +70,7 @@ import jdk.vm.ci.meta.AllocatableValue; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.Value; public class AArch64Move { @@ -92,11 +89,11 @@ public LoadInlineConstant(JavaConstant constant, AllocatableValue result) { @Override public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + AArch64Kind moveKind = (AArch64Kind) result.getPlatformKind(); if (isRegister(result)) { - const2reg(crb, masm, asRegister(result), constant); + const2reg(moveKind, crb, masm, asRegister(result), constant); } else if (isStackSlot(result)) { - StackSlot slot = asStackSlot(result); - const2stack(crb, masm, slot, constant); + const2stack(moveKind, crb, masm, asStackSlot(result), constant); } } @@ -118,16 +115,22 @@ public static class Move extends AArch64LIRInstruction implements ValueMoveOp { @Def({REG, STACK, HINT}) protected AllocatableValue result; @Use({REG, STACK}) protected AllocatableValue input; - public Move(AllocatableValue result, AllocatableValue input) { + private AArch64Kind moveKind; + + public Move(AArch64Kind moveKind, AllocatableValue result, AllocatableValue input) { super(TYPE); this.result = result; this.input = input; + this.moveKind = moveKind; + int resultSize = result.getPlatformKind().getSizeInBytes(); + int inputSize = input.getPlatformKind().getSizeInBytes(); + assert resultSize == moveKind.getSizeInBytes() && resultSize <= inputSize; assert !(isStackSlot(result) && isStackSlot(input)); } @Override public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { - move(crb, masm, getResult(), getInput()); + move(moveKind, crb, masm, getResult(), getInput()); } @Override @@ -232,17 +235,17 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { abstract static class MemOp extends AArch64LIRInstruction implements StandardOp.ImplicitNullCheck { - protected final AArch64Kind kind; + protected final AArch64Kind accessKind; @Use({COMPOSITE}) protected AArch64AddressValue addressValue; @State protected LIRFrameState state; - MemOp(LIRInstructionClass c, AArch64Kind kind, AArch64AddressValue address, LIRFrameState state) { + MemOp(LIRInstructionClass c, AArch64Kind accessKind, AArch64AddressValue address, LIRFrameState state) { super(c); int size = address.getBitMemoryTransferSize(); - assert size == AArch64Address.ANY_SIZE || size == kind.getSizeInBytes() * Byte.SIZE; + assert size == AArch64Address.ANY_SIZE || size == accessKind.getSizeInBytes() * Byte.SIZE; - this.kind = kind; + this.accessKind = accessKind; this.addressValue = address; this.state = state; } @@ -277,28 +280,68 @@ public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int i } } - public static final class LoadOp extends MemOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadOp.class); + public enum ExtendKind { + NONE, + ZERO_EXTEND, + SIGN_EXTEND; + } - @Def protected AllocatableValue result; + abstract static class ExtendableLoadOp extends MemOp { - public LoadOp(AArch64Kind kind, AllocatableValue result, AArch64AddressValue address, LIRFrameState state) { - super(TYPE, kind, address, state); + @Def({REG}) protected AllocatableValue result; + + protected int dstBitSize; + protected ExtendKind extend; + + ExtendableLoadOp(LIRInstructionClass c, AArch64Kind kind, int dstBitSize, ExtendKind extend, AllocatableValue result, AArch64AddressValue address, + LIRFrameState state) { + super(c, kind, address, state); + this.dstBitSize = dstBitSize; + this.extend = extend; this.result = result; } + } + + public static final class LoadOp extends ExtendableLoadOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadOp.class); + + public LoadOp(AArch64Kind accessKind, AllocatableValue result, AArch64AddressValue address, LIRFrameState state) { + this(accessKind, accessKind.getSizeInBytes() * Byte.SIZE, ExtendKind.NONE, result, address, state); + } + + public LoadOp(AArch64Kind accessKind, int dstBitSize, ExtendKind extend, AllocatableValue result, AArch64AddressValue address, LIRFrameState state) { + super(TYPE, accessKind, dstBitSize, extend, result, address, state); + } @Override protected void emitMemAccess(CompilationResultBuilder crb, AArch64MacroAssembler masm) { AArch64Address address = addressValue.toAddress(); Register dst = asRegister(result); - int destSize = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; - int srcSize = kind.getSizeInBytes() * Byte.SIZE; - if (kind.isInteger()) { - masm.ldr(srcSize, dst, address); + int srcBitSize = accessKind.getSizeInBytes() * Byte.SIZE; + if (accessKind.isInteger()) { + switch (extend) { + case NONE: + assert dstBitSize == srcBitSize; + masm.ldr(srcBitSize, dst, address); + break; + case ZERO_EXTEND: + assert dstBitSize >= srcBitSize; + // ldr zeros out remaining bits + masm.ldr(srcBitSize, dst, address); + break; + case SIGN_EXTEND: + assert dstBitSize >= srcBitSize; + // ldrs will sign extend value to required length + masm.ldrs(dstBitSize, srcBitSize, dst, address); + break; + default: + throw GraalError.shouldNotReachHere(); + } } else { - assert srcSize == destSize; - masm.fldr(srcSize, dst, address); + assert extend == ExtendKind.NONE; + assert srcBitSize == dstBitSize && dstBitSize == result.getPlatformKind().getSizeInBytes() * Byte.SIZE; + masm.fldr(srcBitSize, dst, address); } } } @@ -353,7 +396,7 @@ public StoreOp(AArch64Kind kind, AArch64AddressValue address, AllocatableValue i @Override protected void emitMemAccess(CompilationResultBuilder crb, AArch64MacroAssembler masm) { - emitStore(crb, masm, kind, addressValue.toAddress(), input); + emitStore(crb, masm, accessKind, addressValue.toAddress(), input); } } @@ -372,7 +415,7 @@ public StoreConstantOp(AArch64Kind kind, AArch64AddressValue address, JavaConsta @Override public void emitMemAccess(CompilationResultBuilder crb, AArch64MacroAssembler masm) { - emitStore(crb, masm, kind, addressValue.toAddress(), zr.asValue(LIRKind.combine(addressValue))); + emitStore(crb, masm, accessKind, addressValue.toAddress(), zr.asValue(LIRKind.combine(addressValue))); } } @@ -460,26 +503,28 @@ private static void emitStore(@SuppressWarnings("unused") CompilationResultBuild } } - private static void move(CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, Value input) { + private static void move(AArch64Kind moveKind, CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, Value input) { if (isRegister(input)) { + Register src = asRegister(input); if (isRegister(result)) { - reg2reg(crb, masm, result, asAllocatableValue(input)); + reg2reg(moveKind, masm, asRegister(result), src); } else if (isStackSlot(result)) { - reg2stack(crb, masm, asStackSlot(result), asRegister(input)); + reg2stack(moveKind, crb, masm, asStackSlot(result), src); } else { throw GraalError.shouldNotReachHere(); } } else if (isStackSlot(input)) { + StackSlot src = asStackSlot(input); if (isRegister(result)) { - stack2reg(crb, masm, result, asStackSlot(input)); + stack2reg(moveKind, crb, masm, asRegister(result), src); } else if (isStackSlot(result)) { - emitStackMove(crb, masm, result, input); + stack2stack(moveKind, crb, masm, asStackSlot(result), src); } else { throw GraalError.shouldNotReachHere(); } } else if (isJavaConstant(input)) { if (isRegister(result)) { - const2reg(crb, masm, asRegister(result), asJavaConstant(input)); + const2reg(moveKind, crb, masm, asRegister(result), asJavaConstant(input)); } else { throw GraalError.shouldNotReachHere(); } @@ -488,51 +533,43 @@ private static void move(CompilationResultBuilder crb, AArch64MacroAssembler mas } } - private static void emitStackMove(CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, Value input) { + private static void stack2stack(AArch64Kind moveKind, CompilationResultBuilder crb, AArch64MacroAssembler masm, StackSlot result, StackSlot input) { try (ScratchRegister r1 = masm.getScratchRegister()) { try (ScratchRegister r2 = masm.getScratchRegister()) { Register rscratch1 = r1.getRegister(); Register rscratch2 = r2.getRegister(); - // use the slot kind to define the operand size - PlatformKind kind = input.getPlatformKind(); - final int size = kind.getSizeInBytes() * Byte.SIZE; + final int size = moveKind.getSizeInBytes() * Byte.SIZE; // Always perform stack -> stack copies through integer registers crb.blockComment("[stack -> stack copy]"); - AArch64Address src = loadStackSlotAddress(crb, masm, asStackSlot(input), rscratch2); + AArch64Address src = loadStackSlotAddress(size, crb, masm, input, rscratch2); masm.ldr(size, rscratch1, src); - AArch64Address dst = loadStackSlotAddress(crb, masm, asStackSlot(result), rscratch2); + AArch64Address dst = loadStackSlotAddress(size, crb, masm, result, rscratch2); masm.str(size, rscratch1, dst); } } } - private static void reg2reg(@SuppressWarnings("unused") CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, AllocatableValue input) { - Register dst = asRegister(result); - Register src = asRegister(input); - - if (src.equals(dst)) { + private static void reg2reg(AArch64Kind moveKind, AArch64MacroAssembler masm, Register result, Register input) { + if (input.equals(result)) { return; } - AArch64Kind inputKind = (AArch64Kind) input.getPlatformKind(); - AArch64Kind resultKind = (AArch64Kind) result.getPlatformKind(); - final int size = Math.max(Math.min(inputKind.getSizeInBytes(), resultKind.getSizeInBytes()) * Byte.SIZE, 32); - if (dst.getRegisterCategory().equals(CPU) && src.getRegisterCategory().equals(CPU)) { - masm.mov(size, dst, src); + final int size = moveKind.getSizeInBytes() * Byte.SIZE; + assert size == 32 || size == 64 || size == 128; + if (result.getRegisterCategory().equals(CPU) && input.getRegisterCategory().equals(CPU)) { + masm.mov(size, result, input); } else if (size == 128) { - assert dst.getRegisterCategory().equals(SIMD) && src.getRegisterCategory().equals(SIMD); - masm.neon.moveVV(AArch64ASIMDAssembler.ASIMDSize.FullReg, dst, src); + assert result.getRegisterCategory().equals(SIMD) && input.getRegisterCategory().equals(SIMD); + masm.neon.moveVV(AArch64ASIMDAssembler.ASIMDSize.FullReg, result, input); } else { - masm.fmov(size, dst, src); + masm.fmov(size, result, input); } } - static void reg2stack(CompilationResultBuilder crb, AArch64MacroAssembler masm, StackSlot result, Register input) { + static void reg2stack(AArch64Kind moveKind, CompilationResultBuilder crb, AArch64MacroAssembler masm, StackSlot result, Register input) { try (ScratchRegister scratch = masm.getScratchRegister()) { - AArch64Address dest = loadStackSlotAddress(crb, masm, result, scratch.getRegister()); - // use the slot kind to define the operand size - AArch64Kind kind = (AArch64Kind) result.getPlatformKind(); - final int size = kind.getSizeInBytes() * Byte.SIZE; + final int size = moveKind.getSizeInBytes() * Byte.SIZE; + AArch64Address dest = loadStackSlotAddress(size, crb, masm, result, scratch.getRegister()); if (input.getRegisterCategory().equals(CPU)) { masm.str(size, input, dest); } else { @@ -542,25 +579,31 @@ static void reg2stack(CompilationResultBuilder crb, AArch64MacroAssembler masm, } } - static void stack2reg(CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, StackSlot input) { - AArch64Kind kind = (AArch64Kind) input.getPlatformKind(); - // use the slot kind to define the operand size - final int size = kind.getSizeInBytes() * Byte.SIZE; - Register dst = asRegister(result); - if (dst.getRegisterCategory().equals(CPU)) { - AArch64Address src = loadStackSlotAddress(crb, masm, input, result); - masm.ldr(size, dst, src); + static void stack2reg(AArch64Kind moveKind, CompilationResultBuilder crb, AArch64MacroAssembler masm, Register result, StackSlot input) { + /* + * Since AArch64ArithmeticLIRGenerator.emitNarrow creates a move from a QWORD to DWORD, it + * is possible that the stack slot is an aligned QWORD while the moveKind is a DWORD. When + * this happens, it is better treat the move as a QWORD, as this allows an immediate + * addressing mode to be used more often. + */ + final int size = input.getPlatformKind().getSizeInBytes() * Byte.SIZE; + assert moveKind.getSizeInBytes() * Byte.SIZE <= size; + if (result.getRegisterCategory().equals(CPU)) { + AArch64Address src = loadStackSlotAddress(size, crb, masm, input, result); + masm.ldr(size, result, src); } else { - assert dst.getRegisterCategory().equals(SIMD); + assert result.getRegisterCategory().equals(SIMD); try (ScratchRegister sc = masm.getScratchRegister()) { - AArch64Address src = loadStackSlotAddress(crb, masm, input, sc.getRegister()); - masm.fldr(size, dst, src); + AArch64Address src = loadStackSlotAddress(size, crb, masm, input, sc.getRegister()); + masm.fldr(size, result, src); } } } - static void const2reg(CompilationResultBuilder crb, AArch64MacroAssembler masm, Register result, JavaConstant input) { - switch (input.getJavaKind().getStackKind()) { + static void const2reg(AArch64Kind moveKind, CompilationResultBuilder crb, AArch64MacroAssembler masm, Register result, JavaConstant input) { + JavaKind stackKind = input.getJavaKind().getStackKind(); + assert stackKind.isObject() || moveKind.getSizeInBytes() <= stackKind.getByteCount(); + switch (stackKind) { case Int: masm.mov(result, input.asInt()); break; @@ -613,14 +656,14 @@ static void const2reg(CompilationResultBuilder crb, AArch64MacroAssembler masm, } } - static void const2stack(CompilationResultBuilder crb, AArch64MacroAssembler masm, Value result, JavaConstant constant) { + static void const2stack(AArch64Kind moveKind, CompilationResultBuilder crb, AArch64MacroAssembler masm, StackSlot result, JavaConstant constant) { if (constant.isNull() && !crb.mustReplaceWithUncompressedNullRegister(constant)) { - reg2stack(crb, masm, asStackSlot(result), zr); + reg2stack(moveKind, crb, masm, result, zr); } else { try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); - const2reg(crb, masm, scratch, constant); - reg2stack(crb, masm, asStackSlot(result), scratch); + const2reg(moveKind, crb, masm, scratch, constant); + reg2stack(moveKind, crb, masm, result, scratch); } } } @@ -634,19 +677,12 @@ static void const2stack(CompilationResultBuilder crb, AArch64MacroAssembler masm * transfersize, which gives us a 15-bit address range (for longs/doubles) respectively a 14-bit * range (for everything else). * - * @param scratch Scratch register that can be used to load address. If Value.ILLEGAL this - * instruction fails if we try to access a StackSlot that is too large to be loaded - * directly. + * @param scratchReg Scratch register that can be used to load address. * @return AArch64Address of given StackSlot. Uses scratch register if necessary to do so. */ - private static AArch64Address loadStackSlotAddress(CompilationResultBuilder crb, AArch64MacroAssembler masm, StackSlot slot, AllocatableValue scratch) { - Register scratchReg = Value.ILLEGAL.equals(scratch) ? zr : asRegister(scratch); - return loadStackSlotAddress(crb, masm, slot, scratchReg); - } - - private static AArch64Address loadStackSlotAddress(CompilationResultBuilder crb, AArch64MacroAssembler masm, StackSlot slot, Register scratchReg) { + private static AArch64Address loadStackSlotAddress(int size, CompilationResultBuilder crb, AArch64MacroAssembler masm, StackSlot slot, Register scratchReg) { int displacement = crb.frameMap.offsetForStackSlot(slot); - int size = slot.getPlatformKind().getSizeInBytes() * Byte.SIZE; + assert size == slot.getPlatformKind().getSizeInBytes() * Byte.SIZE; return masm.makeAddress(size, sp, displacement, scratchReg); } @@ -672,8 +708,8 @@ protected PointerCompressionOp(LIRInstructionClass ty protected void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { Register resultRegister = getResultRegister(); Register ptr = asRegister(getInput()); - Register base = getBaseRegister(crb); + Register base = getBaseRegister(); // result = (ptr - base) >> shift if (!encoding.hasBase()) { if (encoding.hasShift()) { @@ -759,7 +791,7 @@ private UncompressPointerOp(LIRInstructionClass protected void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { Register inputRegister = asRegister(getInput()); Register resultRegister = getResultRegister(); - Register base = encoding.hasBase() ? getBaseRegister(crb) : null; + Register base = encoding.hasBase() ? getBaseRegister() : null; // result = base + (ptr << shift) if (nonNull || base == null) { diff --git a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64RestoreRegistersOp.java b/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64RestoreRegistersOp.java index edc9b5ba39aa..b0c44ef3bea2 100644 --- a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64RestoreRegistersOp.java +++ b/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64RestoreRegistersOp.java @@ -31,6 +31,7 @@ import java.util.Arrays; +import jdk.vm.ci.aarch64.AArch64Kind; import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; import org.graalvm.compiler.lir.LIRInstructionClass; import org.graalvm.compiler.lir.LIRValueUtil; @@ -75,7 +76,7 @@ protected Register[] getSavedRegisters() { } protected void restoreRegister(CompilationResultBuilder crb, AArch64MacroAssembler masm, Register result, StackSlot input) { - AArch64Move.stack2reg(crb, masm, result.asValue(), input); + AArch64Move.stack2reg((AArch64Kind) input.getPlatformKind(), crb, masm, result, input); } @Override diff --git a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64SaveRegistersOp.java b/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64SaveRegistersOp.java index ea22ff8a131d..a81c4fd6a5a3 100644 --- a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64SaveRegistersOp.java +++ b/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64SaveRegistersOp.java @@ -27,6 +27,7 @@ import static jdk.vm.ci.code.ValueUtil.asStackSlot; import static jdk.vm.ci.code.ValueUtil.isStackSlot; +import jdk.vm.ci.aarch64.AArch64Kind; import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; import org.graalvm.compiler.lir.LIRInstructionClass; @@ -56,7 +57,7 @@ public AArch64SaveRegistersOp(Register[] savedRegisters, AllocatableValue[] save } protected void saveRegister(CompilationResultBuilder crb, AArch64MacroAssembler masm, StackSlot result, Register input) { - AArch64Move.reg2stack(crb, masm, result, input); + AArch64Move.reg2stack((AArch64Kind) result.getPlatformKind(), crb, masm, result, input); } @Override diff --git a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Unary.java b/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Unary.java deleted file mode 100644 index 1b95d3875941..000000000000 --- a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Unary.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.lir.aarch64; - -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; - -import org.graalvm.compiler.asm.aarch64.AArch64Address; -import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; -import org.graalvm.compiler.lir.LIRFrameState; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.StandardOp.ImplicitNullCheck; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.meta.Value; - -/** - * AARCH64 LIR instructions that have one input and one output. - */ -public class AArch64Unary { - - /** - * Instruction with a {@link AArch64AddressValue memory} operand. - */ - public static class MemoryOp extends AArch64LIRInstruction implements ImplicitNullCheck { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MemoryOp.class); - - private final boolean isSigned; - - @Def({REG}) protected AllocatableValue result; - @Use({COMPOSITE}) protected AArch64AddressValue input; - - @State protected LIRFrameState state; - - private int targetSize; - private int srcSize; - - public MemoryOp(boolean isSigned, int targetSize, int srcSize, AllocatableValue result, AArch64AddressValue input, LIRFrameState state) { - super(TYPE); - this.targetSize = targetSize; - this.srcSize = srcSize; - this.isSigned = isSigned; - this.result = result; - this.input = input; - this.state = state; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { - int prePosition = masm.position(); - AArch64Address address = input.toAddress(); - Register dst = asRegister(result); - if (isSigned) { - masm.ldrs(targetSize, srcSize, dst, address); - } else { - masm.ldr(srcSize, dst, address); - } - - if (state != null) { - int implicitExceptionPosition = prePosition; - // Adjust implicit exception position if this ldr/str has been merged to ldp/stp. - if (prePosition == masm.position() && masm.isImmLoadStoreMerged()) { - implicitExceptionPosition = prePosition - 4; - if (crb.isImplicitExceptionExist(implicitExceptionPosition)) { - return; - } - } - crb.recordImplicitException(implicitExceptionPosition, state); - } - } - - @Override - public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { - int displacement = input.getDisplacement(); - if (state == null && value.equals(input.getBase()) && input.getOffset().equals(Value.ILLEGAL) && displacement >= 0 && displacement < implicitNullCheckLimit) { - state = nullCheckState; - return true; - } - return false; - } - } -} diff --git a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ZapRegistersOp.java b/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ZapRegistersOp.java index 296ada715090..7418ec28cd49 100644 --- a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ZapRegistersOp.java +++ b/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ZapRegistersOp.java @@ -24,6 +24,7 @@ */ package org.graalvm.compiler.lir.aarch64; +import jdk.vm.ci.aarch64.AArch64Kind; import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; import org.graalvm.compiler.lir.LIRInstructionClass; import org.graalvm.compiler.lir.Opcode; @@ -60,7 +61,8 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { for (int i = 0; i < zappedRegisters.length; i++) { Register reg = zappedRegisters[i]; if (reg != null) { - AArch64Move.const2reg(crb, masm, reg, zapValues[i]); + AArch64Kind moveKind = (AArch64Kind) crb.target.arch.getPlatformKind(zapValues[i].getJavaKind()); + AArch64Move.const2reg(moveKind, crb, masm, reg, zapValues[i]); } } } diff --git a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ZapStackOp.java b/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ZapStackOp.java index 5e267a5a63ed..4a5534f916bd 100644 --- a/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ZapStackOp.java +++ b/compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ZapStackOp.java @@ -29,6 +29,7 @@ import org.graalvm.compiler.lir.Opcode; import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import jdk.vm.ci.aarch64.AArch64Kind; import jdk.vm.ci.code.StackSlot; import jdk.vm.ci.meta.JavaConstant; @@ -59,7 +60,8 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { for (int i = 0; i < zappedStack.length; i++) { StackSlot slot = zappedStack[i]; if (slot != null) { - AArch64Move.const2stack(crb, masm, slot, zapValues[i]); + AArch64Kind moveKind = (AArch64Kind) crb.target.arch.getPlatformKind(zapValues[i].getJavaKind()); + AArch64Move.const2stack(moveKind, crb, masm, slot, zapValues[i]); } } } diff --git a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Call.java b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Call.java index a4f19259ad29..77b3f11bf0f2 100644 --- a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Call.java +++ b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Call.java @@ -26,7 +26,6 @@ import static jdk.vm.ci.code.ValueUtil.asRegister; import static jdk.vm.ci.code.ValueUtil.isRegister; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; @@ -196,7 +195,7 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { public static void directCall(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget callTarget, Register scratch, boolean align, LIRFrameState info) { int before; - if (scratch != null && !GeneratePIC.getValue(crb.getOptions())) { + if (scratch != null) { assert !align; // offset might not fit a 32-bit immediate, generate an // indirect call with a 64-bit immediate @@ -215,7 +214,7 @@ public static void directCall(CompilationResultBuilder crb, AMD64MacroAssembler public static void directJmp(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget target, Register scratch) { int before; - if (scratch != null && !GeneratePIC.getValue(crb.getOptions())) { + if (scratch != null) { // offset might not fit a 32-bit immediate, generate an // indirect call with a 64-bit immediate before = masm.directJmp(0L, scratch); diff --git a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ControlFlow.java b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ControlFlow.java index 744cd24c7b7c..73cbef8139b2 100644 --- a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ControlFlow.java +++ b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ControlFlow.java @@ -47,6 +47,7 @@ import org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize; import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; import org.graalvm.compiler.code.CompilationResult.JumpTable; +import org.graalvm.compiler.code.CompilationResult.JumpTable.EntryFormat; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.debug.GraalError; @@ -740,7 +741,7 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { } } - JumpTable jt = new JumpTable(jumpTablePos, lowKey, highKey, 4); + JumpTable jt = new JumpTable(jumpTablePos, lowKey, highKey, EntryFormat.OFFSET); crb.compilationResult.addAnnotation(jt); } } @@ -800,13 +801,8 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { masm.jmp(scratchReg); // Inserting padding so that jump the table address is aligned - int entrySize; - if (defaultTarget != null) { - entrySize = 8; - } else { - entrySize = 4; - } - masm.align(entrySize); + EntryFormat entryFormat = defaultTarget == null ? EntryFormat.OFFSET : EntryFormat.KEY2_OFFSET; + masm.align(entryFormat.size); // Patch LEA instruction above now that we know the position of the jump table // this is ugly but there is no better way to do this given the assembler API @@ -834,7 +830,7 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { } } - JumpTable jt = new JumpTable(jumpTablePos, keys[0].asInt(), keys[keys.length - 1].asInt(), entrySize); + JumpTable jt = new JumpTable(jumpTablePos, 0, keys.length - 1, entryFormat); crb.compilationResult.addAnnotation(jt); } } diff --git a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathCosOp.java b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathCosOp.java index 62a466425fe2..f6e22a38f003 100644 --- a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathCosOp.java +++ b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathCosOp.java @@ -204,8 +204,8 @@ @StubPort(path = "src/hotspot/cpu/x86/macroAssembler_x86_cos.cpp", lineStart = 0, lineEnd = 630, - commit = "12bac3a02d7b0f17da78d5ee810fd2742ec43ba6", - sha1 = "1961922e2fb08f172595d18e5fe9bd79d9e3cc7a") + commit = "e58c12e61828485bfffbc9d1b865302b93a94158", + sha1 = "cb83822ed974ba4181ff2d55869b301686e0c8c3") // @formatter:on public final class AMD64MathCosOp extends AMD64MathIntrinsicUnaryOp { diff --git a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathExpOp.java b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathExpOp.java index d717e4817bb8..151a00f889f5 100644 --- a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathExpOp.java +++ b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathExpOp.java @@ -89,8 +89,8 @@ @StubPort(path = "src/hotspot/cpu/x86/macroAssembler_x86_exp.cpp", lineStart = 0, lineEnd = 406, - commit = "51b218842f001f1c4fd5ca7a02a2ba21e9e8a82c", - sha1 = "d21d2a3439932fdbdcf20274798d8488ae1153a9") + commit = "e58c12e61828485bfffbc9d1b865302b93a94158", + sha1 = "e8777563cb0f0f275a490992a36bbdf06bb4c4af") // @formatter:on public final class AMD64MathExpOp extends AMD64MathIntrinsicUnaryOp { diff --git a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathLog10Op.java b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathLog10Op.java index 6972244f26eb..99904c9ce5d0 100644 --- a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathLog10Op.java +++ b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathLog10Op.java @@ -82,8 +82,8 @@ @StubPort(path = "src/hotspot/cpu/x86/macroAssembler_x86_log10.cpp", lineStart = 0, lineEnd = 382, - commit = "12bac3a02d7b0f17da78d5ee810fd2742ec43ba6", - sha1 = "ce7879887e5360ad4c1ca8b776daca5497d6b349") + commit = "e58c12e61828485bfffbc9d1b865302b93a94158", + sha1 = "e03b4280eebe9392433389ab16c4aa52bb01270b") // @formatter:on public final class AMD64MathLog10Op extends AMD64MathIntrinsicUnaryOp { diff --git a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathLogOp.java b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathLogOp.java index c36a872271d4..2cf8c42ebf34 100644 --- a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathLogOp.java +++ b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathLogOp.java @@ -84,8 +84,8 @@ @StubPort(path = "src/hotspot/cpu/x86/macroAssembler_x86_log.cpp", lineStart = 0, lineEnd = 362, - commit = "51b218842f001f1c4fd5ca7a02a2ba21e9e8a82c", - sha1 = "7711be0c6b6e72c57b39578e00000205f1315cde") + commit = "e58c12e61828485bfffbc9d1b865302b93a94158", + sha1 = "4fc26bdb838040042ba0a4f5c04d737705ad4a7a") // @formatter:on public final class AMD64MathLogOp extends AMD64MathIntrinsicUnaryOp { diff --git a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathPowOp.java b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathPowOp.java index cc25c363fc9f..a4b218d6d012 100644 --- a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathPowOp.java +++ b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathPowOp.java @@ -113,8 +113,8 @@ @StubPort(path = "src/hotspot/cpu/x86/macroAssembler_x86_pow.cpp", lineStart = 0, lineEnd = 1880, - commit = "51b218842f001f1c4fd5ca7a02a2ba21e9e8a82c", - sha1 = "b9ee010c248b0a1ccb29e3348fc158eafbe00115") + commit = "e58c12e61828485bfffbc9d1b865302b93a94158", + sha1 = "ff1905731c30cf343460e72d58537d4672b0dce2") // @formatter:on public final class AMD64MathPowOp extends AMD64MathIntrinsicBinaryOp { diff --git a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathSinOp.java b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathSinOp.java index ef63e1e43be7..5b32f31c2c54 100644 --- a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathSinOp.java +++ b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathSinOp.java @@ -207,8 +207,8 @@ @StubPort(path = "src/hotspot/cpu/x86/macroAssembler_x86_sin.cpp", lineStart = 0, lineEnd = 848, - commit = "12bac3a02d7b0f17da78d5ee810fd2742ec43ba6", - sha1 = "2ee75c53633f6044ce351d90bbb79081bfad1663") + commit = "e58c12e61828485bfffbc9d1b865302b93a94158", + sha1 = "4ac9bd6f8b98df9a93ab8ef7de250421605b323c") // @formatter:on public final class AMD64MathSinOp extends AMD64MathIntrinsicUnaryOp { diff --git a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathTanOp.java b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathTanOp.java index d2ebccf59bfd..917e1f89419a 100644 --- a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathTanOp.java +++ b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64MathTanOp.java @@ -133,8 +133,8 @@ @StubPort(path = "src/hotspot/cpu/x86/macroAssembler_x86_tan.cpp", lineStart = 0, lineEnd = 1059, - commit = "12bac3a02d7b0f17da78d5ee810fd2742ec43ba6", - sha1 = "466fa030d8bf2c1ba0630839bce6f46549a4ebe0") + commit = "e58c12e61828485bfffbc9d1b865302b93a94158", + sha1 = "1f1f3a6d2437b250c0d5b13e596d9ed5a14c869e") // @formatter:on public final class AMD64MathTanOp extends AMD64MathIntrinsicUnaryOp { diff --git a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java index ce51b09f38b7..d4e16ac76f4f 100644 --- a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java +++ b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java @@ -31,7 +31,6 @@ import static jdk.vm.ci.code.ValueUtil.isStackSlot; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag.Equal; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag.NotEqual; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; @@ -63,7 +62,6 @@ import org.graalvm.compiler.lir.StandardOp.ValueMoveOp; import org.graalvm.compiler.lir.VirtualStackSlot; import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.options.OptionValues; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.amd64.AMD64Kind; @@ -834,8 +832,8 @@ protected PointerCompressionOp(LIRInstructionClass @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - Register baseReg = getBaseRegister(crb); + Register baseReg = getBaseRegister(); int shift = getShift(); Register resReg = getResultRegister(); if (nonNull && !baseReg.equals(Register.None) && getInput() instanceof RegisterValue) { diff --git a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/vector/AMD64VectorShuffle.java b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/vector/AMD64VectorShuffle.java index 4c33ab5d2303..59560c77ab49 100644 --- a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/vector/AMD64VectorShuffle.java +++ b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/vector/AMD64VectorShuffle.java @@ -42,6 +42,7 @@ import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexMRIOp.VPEXTRQ; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexMRIOp.VPEXTRW; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexMoveOp.VMOVD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexMoveOp.VMOVDQU64; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexMoveOp.VMOVQ; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMIOp.VINSERTF128; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMIOp.VINSERTF32X4; @@ -55,18 +56,22 @@ import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMIOp.VINSERTI64X4; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMIOp.VSHUFPD; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMIOp.VSHUFPS; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp.VPERMT2B; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp.VPSHUFB; import static org.graalvm.compiler.asm.amd64.AVXKind.AVXSize.XMM; import static org.graalvm.compiler.asm.amd64.AVXKind.AVXSize.ZMM; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import jdk.vm.ci.code.Register; import org.graalvm.compiler.asm.amd64.AMD64Address; import org.graalvm.compiler.asm.amd64.AMD64Assembler.VexMRIOp; import org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRMIOp; import org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMIOp; +import org.graalvm.compiler.asm.amd64.AMD64BaseAssembler; import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; import org.graalvm.compiler.asm.amd64.AVXKind; +import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.lir.LIRInstructionClass; import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; @@ -75,6 +80,7 @@ import jdk.vm.ci.amd64.AMD64.CPUFeature; import jdk.vm.ci.amd64.AMD64Kind; import jdk.vm.ci.meta.AllocatableValue; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; public class AMD64VectorShuffle { @@ -150,6 +156,51 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { } } + public static final class ConstPermuteBytesUsingTableOp extends AMD64LIRInstruction implements AVX512Support { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ConstPermuteBytesUsingTableOp.class); + @Def({REG}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue source; + @Use({REG}) protected AllocatableValue mask; + @Temp({REG}) protected AllocatableValue selector; + + byte[] selectorData; + + public ConstPermuteBytesUsingTableOp(LIRGeneratorTool tool, AllocatableValue result, AllocatableValue source, byte[] selectorData) { + this(tool, result, source, selectorData, null); + } + + public ConstPermuteBytesUsingTableOp(LIRGeneratorTool tool, AllocatableValue result, AllocatableValue source, byte[] selectorData, AllocatableValue mask) { + super(TYPE); + this.result = result; + this.source = source; + this.selectorData = selectorData; + this.selector = tool.newVariable(LIRKind.value(source.getPlatformKind())); + this.mask = mask; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Kind kind = (AMD64Kind) source.getPlatformKind(); + int alignment = crb.dataBuilder.ensureValidDataAlignment(selectorData.length); + AMD64Address address = (AMD64Address) crb.recordDataReferenceInCode(selectorData, alignment); + VMOVDQU64.emit(masm, AVXKind.getRegisterSize(kind), asRegister(selector), address); + if (isRegister(source)) { + VPERMT2B.emit(masm, AVXKind.getRegisterSize(kind), asRegister(result), asRegister(selector), asRegister(source), mask != null ? asRegister(mask) : Register.None, + AMD64BaseAssembler.EVEXPrefixConfig.Z1, + AMD64BaseAssembler.EVEXPrefixConfig.B0); + } else { + VPERMT2B.emit(masm, AVXKind.getRegisterSize(kind), asRegister(result), asRegister(selector), (AMD64Address) crb.asAddress(source), mask != null ? asRegister(mask) : Register.None, + AMD64BaseAssembler.EVEXPrefixConfig.Z1, + AMD64BaseAssembler.EVEXPrefixConfig.B0); + } + } + + @Override + public AllocatableValue getOpmask() { + return mask; + } + } + public static final class ConstShuffleBytesOp extends AMD64LIRInstruction { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ConstShuffleBytesOp.class); @Def({REG}) protected AllocatableValue result; @@ -176,13 +227,17 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { public static class ShuffleWordOp extends AMD64LIRInstruction { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ShuffleWordOp.class); - private final VexRMIOp op; + protected final VexRMIOp op; @Def({REG}) protected AllocatableValue result; @Use({REG, STACK}) protected AllocatableValue source; - private final int selector; + protected final int selector; public ShuffleWordOp(VexRMIOp op, AllocatableValue result, AllocatableValue source, int selector) { - super(TYPE); + this(TYPE, op, result, source, selector); + } + + protected ShuffleWordOp(LIRInstructionClass c, VexRMIOp op, AllocatableValue result, AllocatableValue source, int selector) { + super(c); this.op = op; this.result = result; this.source = source; @@ -200,6 +255,34 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { } } + public static class ShuffleWordOpWithMask extends ShuffleWordOp implements AVX512Support { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ShuffleWordOpWithMask.class); + + @Use({REG}) protected AllocatableValue mask; + + public ShuffleWordOpWithMask(VexRMIOp op, AllocatableValue result, AllocatableValue source, int selector, AllocatableValue mask) { + super(TYPE, op, result, source, selector); + this.mask = mask; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Kind kind = (AMD64Kind) source.getPlatformKind(); + if (isRegister(source)) { + op.emit(masm, AVXKind.getRegisterSize(kind), asRegister(result), asRegister(source), selector, asRegister(mask), AMD64BaseAssembler.EVEXPrefixConfig.Z1, + AMD64BaseAssembler.EVEXPrefixConfig.B0); + } else { + op.emit(masm, AVXKind.getRegisterSize(kind), asRegister(result), (AMD64Address) crb.asAddress(source), selector, asRegister(mask), AMD64BaseAssembler.EVEXPrefixConfig.Z1, + AMD64BaseAssembler.EVEXPrefixConfig.B0); + } + } + + @Override + public AllocatableValue getOpmask() { + return mask; + } + } + public static class ShuffleFloatOp extends AMD64LIRInstruction { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ShuffleFloatOp.class); @Def({REG}) protected AllocatableValue result; diff --git a/compiler/src/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java b/compiler/src/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java index d8bab3b08f7e..aa238727d126 100644 --- a/compiler/src/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java +++ b/compiler/src/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java @@ -737,14 +737,10 @@ void recordMark(CompilationResult.CodeMark m) { } } - public CallContext openCallContext(boolean direct) { + public CallContext openCallContext() { if (currentCallContext != null) { throw GraalError.shouldNotReachHere("Call context already open"); } - // Currently only AOT requires call context information and only for direct calls. - if (compilationResult.isImmutablePIC() && direct) { - currentCallContext = new CallContext(); - } return currentCallContext; } diff --git a/compiler/src/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/hashing/IntHasher.java b/compiler/src/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/hashing/IntHasher.java index 8018d4179340..962dfad82e77 100644 --- a/compiler/src/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/hashing/IntHasher.java +++ b/compiler/src/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/hashing/IntHasher.java @@ -45,7 +45,7 @@ private IntHasher(int cardinality, short factor, byte shift) { this.shift = shift; } - // 1 + the first 9999 prime numbers + // 1 + the first 999 prime numbers private static final Short[] factors = new Short[1000]; static { diff --git a/compiler/src/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java b/compiler/src/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java index 077c2dbb5639..45ae54366be8 100644 --- a/compiler/src/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java +++ b/compiler/src/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java @@ -100,7 +100,6 @@ protected void run(final StructuredGraph graph, final CoreProviders context) { propagateFixed(d, d, context, lazyLoops); } } - if (context != null) { for (FixedGuardNode fixedGuard : graph.getNodes(FixedGuardNode.TYPE)) { try (DebugCloseable closable = fixedGuard.withNodeSourcePosition()) { @@ -108,7 +107,6 @@ protected void run(final StructuredGraph graph, final CoreProviders context) { } } } - new DeadCodeEliminationPhase(Optional).apply(graph); } @@ -269,6 +267,9 @@ private static boolean isCountedLoopExit(IfNode ifNode, LazyValue laz if (loopEx.detectCounted()) { return ifNode == loopEx.counted().getLimitTest(); } + if (loopEx.canBecomeLimitTestAfterFloatingReads(ifNode)) { + return true; + } } return false; } diff --git a/compiler/src/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPartialUnrollPhase.java b/compiler/src/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPartialUnrollPhase.java index de173df37bd0..56fea99a1af7 100644 --- a/compiler/src/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPartialUnrollPhase.java +++ b/compiler/src/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPartialUnrollPhase.java @@ -47,63 +47,82 @@ public LoopPartialUnrollPhase(LoopPolicies policies, CanonicalizerPhase canonica this.canonicalizer = canonicalizer; } - @Override @SuppressWarnings("try") - protected void run(StructuredGraph graph, CoreProviders context) { - if (graph.hasLoops()) { - EconomicSetNodeEventListener listener = new EconomicSetNodeEventListener(); - boolean changed = true; - EconomicMap opaqueUnrolledStrides = null; - boolean prePostInserted = false; - while (changed) { - changed = false; - try (Graph.NodeEventScope nes = graph.trackNodeEvents(listener)) { - LoopsData dataCounted = context.getLoopsDataProvider().getLoopsData(graph); - dataCounted.detectedCountedLoops(); - Graph.Mark mark = graph.getMark(); - for (LoopEx loop : dataCounted.countedLoops()) { - if (!LoopTransformations.isUnrollableLoop(loop)) { - continue; - } - if (getPolicies().shouldPartiallyUnroll(loop, context)) { - if (loop.loopBegin().isSimpleLoop()) { - // First perform the pre/post transformation and do the partial - // unroll when we come around again. - LoopTransformations.insertPrePostLoops(loop); - prePostInserted = true; - changed = true; - } else if (prePostInserted) { - if (opaqueUnrolledStrides == null) { - opaqueUnrolledStrides = EconomicMap.create(Equivalence.IDENTITY); - } - LoopTransformations.partialUnroll(loop, opaqueUnrolledStrides); - changed = true; + private void unroll(StructuredGraph graph, CoreProviders context) { + /* + * We run a canonicalizer without simplification here because simplifications after + * inserting pre/main/post can make loops non-counted: For example the ifNode swap + * optimization can cause the counted condition being swapped with another one destroying + * counted loop info. + */ + final CanonicalizerPhase canonicalizerWithoutSimplification = canonicalizer.copyWithoutSimplification(); + EconomicSetNodeEventListener listener = new EconomicSetNodeEventListener(); + boolean changed = true; + EconomicMap opaqueUnrolledStrides = null; + boolean prePostInserted = false; + while (changed) { + changed = false; + try (Graph.NodeEventScope nes = graph.trackNodeEvents(listener)) { + LoopsData dataCounted = context.getLoopsDataProvider().getLoopsData(graph); + dataCounted.detectedCountedLoops(); + Graph.Mark mark = graph.getMark(); + for (LoopEx loop : dataCounted.countedLoops()) { + if (!LoopTransformations.isUnrollableLoop(loop)) { + continue; + } + if (getPolicies().shouldPartiallyUnroll(loop, context)) { + if (loop.loopBegin().isSimpleLoop()) { + // First perform the pre/post transformation and do the partial + // unroll when we come around again. + LoopTransformations.insertPrePostLoops(loop); + prePostInserted = true; + changed = true; + } else if (prePostInserted) { + if (opaqueUnrolledStrides == null) { + opaqueUnrolledStrides = EconomicMap.create(Equivalence.IDENTITY); } + LoopTransformations.partialUnroll(loop, opaqueUnrolledStrides); + changed = true; } } - dataCounted.deleteUnusedNodes(); - - if (!listener.getNodes().isEmpty()) { - canonicalizer.applyIncremental(graph, context, listener.getNodes()); - listener.getNodes().clear(); - } + } + dataCounted.deleteUnusedNodes(); - assert !prePostInserted || checkCounted(graph, context.getLoopsDataProvider(), mark); + if (!listener.getNodes().isEmpty()) { + canonicalizerWithoutSimplification.applyIncremental(graph, context, listener.getNodes()); + listener.getNodes().clear(); } + + assert !prePostInserted || checkCounted(graph, context.getLoopsDataProvider(), mark); } - if (opaqueUnrolledStrides != null) { - try (Graph.NodeEventScope nes = graph.trackNodeEvents(listener)) { - for (OpaqueNode opaque : opaqueUnrolledStrides.getValues()) { - opaque.remove(); - } - if (!listener.getNodes().isEmpty()) { - canonicalizer.applyIncremental(graph, context, listener.getNodes()); - } + } + if (opaqueUnrolledStrides != null) { + try (Graph.NodeEventScope nes = graph.trackNodeEvents(listener)) { + for (OpaqueNode opaque : opaqueUnrolledStrides.getValues()) { + opaque.remove(); + } + if (!listener.getNodes().isEmpty()) { + canonicalizer.applyIncremental(graph, context, listener.getNodes()); } } } } + @Override + @SuppressWarnings("try") + protected void run(StructuredGraph graph, CoreProviders context) { + EconomicSetNodeEventListener listener = new EconomicSetNodeEventListener(); + if (graph.hasLoops()) { + try (Graph.NodeEventScope nes = graph.trackNodeEvents(listener)) { + unroll(graph, context); + } + if (!listener.getNodes().isEmpty()) { + // run a regular canonicalization with simplification after the entire unrolling + canonicalizer.applyIncremental(graph, context, listener.getNodes()); + } + } + } + private static boolean checkCounted(StructuredGraph graph, LoopsDataProvider loopsDataProvider, Graph.Mark mark) { LoopsData dataCounted; dataCounted = loopsDataProvider.getLoopsData(graph); diff --git a/compiler/src/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java b/compiler/src/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java index e400b0f1065e..90510c6243cb 100644 --- a/compiler/src/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java +++ b/compiler/src/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java @@ -55,7 +55,6 @@ import org.graalvm.compiler.nodes.LoopExitNode; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.PhiNode; -import org.graalvm.compiler.nodes.ProfileData.LoopFrequencyData; import org.graalvm.compiler.nodes.ProxyNode; import org.graalvm.compiler.nodes.SafepointNode; import org.graalvm.compiler.nodes.StateSplit; @@ -63,6 +62,7 @@ import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage; import org.graalvm.compiler.nodes.StructuredGraph.StageFlag; import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.ProfileData.BranchProbabilityData; import org.graalvm.compiler.nodes.VirtualState.NodePositionClosure; import org.graalvm.compiler.nodes.calc.AddNode; import org.graalvm.compiler.nodes.calc.CompareNode; @@ -92,12 +92,17 @@ private LoopTransformations() { public static void peel(LoopEx loop) { loop.detectCounted(); - loop.inside().duplicate().insertBefore(loop); + double frequencyBefore = -1D; + AbstractBeginNode countedExit = null; if (loop.isCounted()) { - // For counted loops we assume that we have an effect on the loop frequency. - loop.loopBegin().setLoopFrequency(loop.loopBegin().profileData().decrementFrequency(1.0)); + frequencyBefore = loop.localLoopFrequency(); + countedExit = loop.counted().getCountedExit(); } + loop.inside().duplicate().insertBefore(loop); loop.loopBegin().incrementPeelings(); + if (countedExit != null) { + adaptCountedLoopExitProbability(countedExit, frequencyBefore - 1D); + } } @SuppressWarnings("try") @@ -208,20 +213,9 @@ public static void unswitch(LoopEx loop, List controlSplitNode public static void partialUnroll(LoopEx loop, EconomicMap opaqueUnrolledStrides) { assert loop.loopBegin().isMainLoop(); loop.loopBegin().graph().getDebug().log("LoopPartialUnroll %s", loop); - + adaptCountedLoopExitProbability(loop.counted().getCountedExit(), loop.localLoopFrequency() / 2D); LoopFragmentInside newSegment = loop.inside().duplicate(); newSegment.insertWithinAfter(loop, opaqueUnrolledStrides); - - // Try to update the corresponding post loop's frequency. - for (LoopExitNode exit : loop.loopBegin().loopExits()) { - if (exit.next().hasExactlyOneUsage() && exit.next().usages().first() instanceof LoopBeginNode) { - LoopBeginNode possiblePostLoopBegin = (LoopBeginNode) exit.next().usages().first(); - if (possiblePostLoopBegin.isPostLoop()) { - possiblePostLoopBegin.setLoopFrequency(loop.loopBegin().profileData().copy(loop.loopBegin().getUnrollFactor() - 1)); - break; - } - } - } } /** @@ -416,14 +410,18 @@ public static PreMainPostResult insertPrePostLoops(LoopEx loop) { } else { updatePreLoopLimit(preCounted); } - double originalFrequency = loop.loopBegin().loopFrequency(); - preLoopBegin.setLoopFrequency(LoopFrequencyData.injected(1.0)); - mainLoopBegin.setLoopFrequency(mainLoopBegin.profileData().decrementFrequency(2.0)); - postLoopBegin.setLoopFrequency(LoopFrequencyData.injected(1.0)); + double originalFrequency = loop.localLoopFrequency(); preLoopBegin.setLoopOrigFrequency(originalFrequency); mainLoopBegin.setLoopOrigFrequency(originalFrequency); postLoopBegin.setLoopOrigFrequency(originalFrequency); + assert preLoopExitNode.predecessor() instanceof IfNode; + assert mainLoopExitNode.predecessor() instanceof IfNode; + assert postLoopExitNode.predecessor() instanceof IfNode; + + setSingleVisitedLoopFrequencySplitProbability(preLoopExitNode); + setSingleVisitedLoopFrequencySplitProbability(postLoopExitNode); + if (graph.isAfterStage(StageFlag.VALUE_PROXY_REMOVAL)) { // The pre and post loops don't require safepoints at all for (SafepointNode safepoint : preLoop.nodes().filter(SafepointNode.class)) { @@ -438,6 +436,27 @@ public static PreMainPostResult insertPrePostLoops(LoopEx loop) { return new PreMainPostResult(preLoopBegin, mainLoopBegin, postLoopBegin, preLoop, mainLoop, postLoop); } + /** + * Inject a split probability for the (counted) loop check that will result in a loop frequency + * of 1 (in case this is the only loop exit). + */ + private static void setSingleVisitedLoopFrequencySplitProbability(AbstractBeginNode lex) { + IfNode ifNode = ((IfNode) lex.predecessor()); + boolean trueSucc = ifNode.trueSuccessor() == lex; + ifNode.setTrueSuccessorProbability(BranchProbabilityData.injected(0.01, trueSucc)); + } + + public static void adaptCountedLoopExitProbability(AbstractBeginNode lex, double newFrequency) { + double d = Math.abs(1D - newFrequency); + if (d <= 1D) { + setSingleVisitedLoopFrequencySplitProbability(lex); + return; + } + IfNode ifNode = ((IfNode) lex.predecessor()); + boolean trueSucc = ifNode.trueSuccessor() == lex; + ifNode.setTrueSuccessorProbability(BranchProbabilityData.injected((newFrequency - 1) / newFrequency, trueSucc)); + } + public static class PreMainPostResult { private final LoopBeginNode preLoop; private final LoopBeginNode mainLoop; diff --git a/compiler/src/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/SpeculativeGuardMovementPhase.java b/compiler/src/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/SpeculativeGuardMovementPhase.java index f8735ab9788a..fa934c5b800f 100644 --- a/compiler/src/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/SpeculativeGuardMovementPhase.java +++ b/compiler/src/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/SpeculativeGuardMovementPhase.java @@ -41,12 +41,13 @@ import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.PhiNode; +import org.graalvm.compiler.nodes.ProfileData.BranchProbabilityData; +import org.graalvm.compiler.nodes.ProfileData.ProfileSource; import org.graalvm.compiler.nodes.ShortCircuitOrNode; import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.StageFlag; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.WithExceptionNode; -import org.graalvm.compiler.nodes.ProfileData.BranchProbabilityData; -import org.graalvm.compiler.nodes.StructuredGraph.StageFlag; import org.graalvm.compiler.nodes.calc.CompareNode; import org.graalvm.compiler.nodes.calc.IntegerBelowNode; import org.graalvm.compiler.nodes.calc.IntegerConvertNode; @@ -181,6 +182,7 @@ private Block earliestBlock(Node node) { if (node instanceof GuardNode) { GuardNode guard = (GuardNode) node; LogicNode condition = guard.getCondition(); + Loop forcedHoisting = null; if (condition instanceof IntegerLessThanNode || condition instanceof IntegerBelowNode) { forcedHoisting = tryOptimizeCompare(guard, (CompareNode) condition); @@ -252,17 +254,12 @@ private Loop tryOptimizeCompare(GuardNode guard, CompareNode compare) { bound = compare.getY(); mirrored = false; } + if (tryOptimizeCompare(compare, iv, bound, mirrored, guard)) { - if (isInverted(iv.getLoop())) { - return null; - } return iv.getLoop().loop(); } if (otherIV != null) { if (tryOptimizeCompare(compare, otherIV, iv.valueNode(), !mirrored, guard)) { - if (isInverted(iv.getLoop())) { - return null; - } return otherIV.getLoop().loop(); } } @@ -420,7 +417,6 @@ private boolean shouldOptimizeCompare(InductionVariable iv, ValueNode bound, Gua return false; // the bound must be loop invariant and schedulable above the loop. } - LoopBeginNode loopBeginNode = loopEx.loopBegin(); CountedLoopInfo countedLoop = loopEx.counted(); if (profilingInfo != null && !(profilingInfo instanceof DefaultProfilingInfo)) { @@ -435,7 +431,8 @@ private boolean shouldOptimizeCompare(InductionVariable iv, ValueNode bound, Gua loopFreqThreshold++; } } - if (loopBeginNode.loopFrequency() < loopFreqThreshold) { + if (ProfileSource.isTrusted(loopEx.localFrequencySource()) && + loopEx.localLoopFrequency() < loopFreqThreshold) { debug.log("shouldOptimizeCompare(%s):loop frequency too low.", guard); // loop frequency is too low -- the complexity introduced by hoisting this guard // will not pay off. diff --git a/compiler/src/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java b/compiler/src/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java index 50f392394f9f..15d150ae2f63 100644 --- a/compiler/src/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java +++ b/compiler/src/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java @@ -35,7 +35,6 @@ import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.graph.iterators.NodeIterable; -import org.graalvm.compiler.java.ComputeLoopFrequenciesClosure; import org.graalvm.compiler.loop.phases.LoopPartialUnrollPhase; import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.StructuredGraph; @@ -315,7 +314,6 @@ public String toString(Verbosity verbosity) { new FloatingReadPhase().apply(graph); new DeadCodeEliminationPhase().apply(graph); new ConditionalEliminationPhase(true).apply(graph, context); - ComputeLoopFrequenciesClosure.compute(graph); new GuardLoweringPhase().apply(graph, context); new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, context); new FrameStateAssignmentPhase().apply(graph); diff --git a/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/SchedulePhaseBenchmark.java b/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/SchedulePhaseBenchmark.java index f9d1e8bfb278..940c0f836b55 100644 --- a/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/SchedulePhaseBenchmark.java +++ b/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/SchedulePhaseBenchmark.java @@ -39,7 +39,7 @@ public static class StringEquals extends ScheduleState { @Benchmark public void stringEquals(StringEquals s) { - s.schedule.apply(s.graph); + SchedulePhase.runWithoutContextOptimizations(s.graph); } @Benchmark @@ -95,7 +95,7 @@ public IntersectionState_LATEST_OPTIMAL() { @Benchmark public void intersection_LATEST_OPTIMAL(IntersectionState_LATEST_OPTIMAL s) { - s.schedule.apply(s.graph); + SchedulePhase.runWithoutContextOptimizations(s.graph, s.getSelectedStrategy()); } @MethodSpec(declaringClass = SchedulePhaseBenchmark.class, name = "intersectionSnippet") @@ -107,7 +107,7 @@ public IntersectionState_LATEST_OUT_OF_LOOPS_OPTIMAL() { @Benchmark public void intersection_LATEST_OUT_OF_LOOPS_OPTIMAL(IntersectionState_LATEST_OUT_OF_LOOPS_OPTIMAL s) { - s.schedule.apply(s.graph); + SchedulePhase.runWithoutContextOptimizations(s.graph, s.getSelectedStrategy()); } @MethodSpec(declaringClass = SchedulePhaseBenchmark.class, name = "intersectionSnippet") @@ -119,7 +119,7 @@ public IntersectionState_EARLIEST_OPTIMAL() { @Benchmark public void intersection_EARLIEST_OPTIMAL(IntersectionState_EARLIEST_OPTIMAL s) { - s.schedule.apply(s.graph); + SchedulePhase.runWithoutContextOptimizations(s.graph, s.getSelectedStrategy()); } @MethodSpec(declaringClass = SchedulePhaseBenchmark.class, name = "intersectionSnippet") @@ -131,7 +131,7 @@ public IntersectionState_EARLIEST_WITH_GUARD_ORDER_OPTIMAL() { @Benchmark public void intersection_EARLIEST_WITH_GUARD_ORDER_OPTIMAL(IntersectionState_EARLIEST_WITH_GUARD_ORDER_OPTIMAL s) { - s.schedule.apply(s.graph); + SchedulePhase.runWithoutContextOptimizations(s.graph, s.getSelectedStrategy()); } // Checkstyle: resume method name check @@ -145,7 +145,7 @@ public ScheduleEarliestIterative_LATEST_OPTIMAL() { @Benchmark public void scheduleEarliestIterative_LATEST_OPTIMAL(ScheduleEarliestIterative_LATEST_OPTIMAL s) { - s.schedule.apply(s.graph); + SchedulePhase.runWithoutContextOptimizations(s.graph, s.getSelectedStrategy()); } @MethodSpec(declaringClass = SchedulePhase.Instance.class, name = "scheduleEarliestIterative") @@ -157,7 +157,7 @@ public ScheduleEarliestIterative_LATEST_OUT_OF_LOOPS_OPTIMAL() { @Benchmark public void scheduleEarliestIterative_LATEST_OUT_OF_LOOPS_OPTIMAL(ScheduleEarliestIterative_LATEST_OUT_OF_LOOPS_OPTIMAL s) { - s.schedule.apply(s.graph); + SchedulePhase.runWithoutContextOptimizations(s.graph, s.getSelectedStrategy()); } @MethodSpec(declaringClass = SchedulePhase.Instance.class, name = "scheduleEarliestIterative") @@ -169,7 +169,7 @@ public ScheduleEarliestIterative_EARLIEST_OPTIMAL() { @Benchmark public void scheduleEarliestIterative_EARLIEST_OPTIMAL(ScheduleEarliestIterative_EARLIEST_OPTIMAL s) { - s.schedule.apply(s.graph); + SchedulePhase.runWithoutContextOptimizations(s.graph, s.getSelectedStrategy()); } @MethodSpec(declaringClass = SchedulePhase.Instance.class, name = "scheduleEarliestIterative") @@ -181,7 +181,7 @@ public ScheduleEarliestIterative_EARLIEST_WITH_GUARD_ORDER_OPTIMAL() { @Benchmark public void scheduleEarliestIterative_EARLIEST_WITH_GUARD_ORDER_OPTIMAL(ScheduleEarliestIterative_EARLIEST_WITH_GUARD_ORDER_OPTIMAL s) { - s.schedule.apply(s.graph); + SchedulePhase.runWithoutContextOptimizations(s.graph, s.getSelectedStrategy()); } // Checkstyle: resume method name check } diff --git a/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/FrameStateAssignmentState.java b/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/FrameStateAssignmentState.java index 5848addc694e..b491ed03b64b 100644 --- a/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/FrameStateAssignmentState.java +++ b/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/FrameStateAssignmentState.java @@ -34,7 +34,7 @@ public class FrameStateAssignmentState extends GraphState { @Override protected StructuredGraph preprocessOriginal(StructuredGraph structuredGraph) { - new GuardLoweringPhase().apply(structuredGraph, null); + new GuardLoweringPhase().apply(structuredGraph, graal.providers); return structuredGraph; } diff --git a/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/GraphState.java b/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/GraphState.java index 158a9ca7ec7b..e6f6cacedd37 100644 --- a/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/GraphState.java +++ b/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/GraphState.java @@ -44,9 +44,11 @@ @State(Scope.Thread) public abstract class GraphState { + final GraalState graal; + @SuppressWarnings("try") public GraphState() { - GraalState graal = new GraalState(); + graal = new GraalState(); DebugContext debug = graal.debug; ResolvedJavaMethod method = graal.metaAccess.lookupJavaMethod(getMethodFromMethodSpec(getClass())); StructuredGraph structuredGraph = null; diff --git a/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/ScheduleState.java b/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/ScheduleState.java index 434d5a30f717..9c621cddb796 100644 --- a/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/ScheduleState.java +++ b/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/ScheduleState.java @@ -27,14 +27,11 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.phases.OptimisticOptimizations; import org.graalvm.compiler.phases.PhaseSuite; -import org.graalvm.compiler.phases.schedule.SchedulePhase; import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; import org.graalvm.compiler.phases.tiers.HighTierContext; public class ScheduleState extends GraphState { - public SchedulePhase schedule; - private final SchedulingStrategy selectedStrategy; public ScheduleState(SchedulingStrategy selectedStrategy) { @@ -45,10 +42,8 @@ public ScheduleState() { this(SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER); } - @Override - public void beforeInvocation() { - schedule = new SchedulePhase(selectedStrategy); - super.beforeInvocation(); + public SchedulingStrategy getSelectedStrategy() { + return selectedStrategy; } @Override diff --git a/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java b/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java index 2e003bb1ec33..6436a169062a 100644 --- a/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java +++ b/compiler/src/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java @@ -466,9 +466,9 @@ protected final void emitCode() { int bytecodeSize = request.graph.method() == null ? 0 : request.graph.getBytecodeSize(); SpeculationLog speculationLog = null; request.compilationResult.setHasUnsafeAccess(request.graph.hasUnsafeAccess()); - LIRCompilerBackend.emitCode(request.backend, request.graph.getAssumptions(), request.graph.method(), request.graph.getMethods(), request.graph.getFields(), - speculationLog, bytecodeSize, lirGenRes, - request.compilationResult, request.installedCodeOwner, request.factory); + LIRCompilerBackend.emitCode(request.backend, request.graph.getAssumptions(), request.graph.method(), request.graph.getMethods(), speculationLog, + bytecodeSize, lirGenRes, request.compilationResult, + request.installedCodeOwner, request.factory); } protected StructuredGraph graph() { diff --git a/compiler/src/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/InputType.java b/compiler/src/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/InputType.java index 3f064e5ed331..78e41d7c35d1 100644 --- a/compiler/src/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/InputType.java +++ b/compiler/src/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/InputType.java @@ -24,6 +24,9 @@ */ package org.graalvm.compiler.nodeinfo; +/** + * Constants denoting how a node is using an input node. + */ public enum InputType { /** * Inputs that consume an actual value generated by the referenced node. diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/CanonicalizableLocation.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/CanonicalizableLocation.java index 39a4de9a1301..becd2a74e232 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/CanonicalizableLocation.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/CanonicalizableLocation.java @@ -24,9 +24,9 @@ */ package org.graalvm.compiler.nodes; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.nodes.spi.CoreProviders; public interface CanonicalizableLocation { - ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool); + ValueNode canonicalizeRead(ValueNode read, AddressNode address, ValueNode object, CoreProviders tool); } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/CompressionNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/CompressionNode.java index ea45cb8d368a..38d05fec7840 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/CompressionNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/CompressionNode.java @@ -24,7 +24,6 @@ */ package org.graalvm.compiler.nodes; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2; @@ -33,18 +32,18 @@ import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.lir.gen.LIRGeneratorTool; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.calc.ConvertNode; import org.graalvm.compiler.nodes.calc.UnaryNode; +import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.nodes.type.StampTool; import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.Value; /** @@ -125,11 +124,6 @@ public CompressEncoding getEncoding() { @Override public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { if (forValue.isConstant()) { - if (GeneratePIC.getValue(tool.getOptions())) { - // We always want uncompressed constants - return this; - } - ConstantNode constant = (ConstantNode) forValue; return ConstantNode.forConstant(stamp(NodeView.DEFAULT), convert(constant.getValue(), tool.getConstantReflection()), constant.getStableDimension(), constant.isDefaultStable(), tool.getMetaAccess()); diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EncodedGraph.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EncodedGraph.java index 147b980f2a27..5783821b9dc4 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EncodedGraph.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EncodedGraph.java @@ -26,11 +26,9 @@ import java.util.List; -import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.graph.NodeClass; import jdk.vm.ci.meta.Assumptions; -import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; /** @@ -47,7 +45,6 @@ public class EncodedGraph { private final Assumptions assumptions; private final List inlinedMethods; private final boolean trackNodeSourcePosition; - private final EconomicSet fields; private final boolean hasUnsafeAccess; /** @@ -57,12 +54,11 @@ public class EncodedGraph { protected int[] nodeStartOffsets; public EncodedGraph(byte[] encoding, int startOffset, Object[] objects, NodeClass[] types, StructuredGraph sourceGraph) { - this(encoding, startOffset, objects, types, sourceGraph.getAssumptions(), sourceGraph.getMethods(), sourceGraph.getFields(), sourceGraph.hasUnsafeAccess(), - sourceGraph.trackNodeSourcePosition()); + this(encoding, startOffset, objects, types, sourceGraph.getAssumptions(), sourceGraph.getMethods(), sourceGraph.hasUnsafeAccess(), sourceGraph.trackNodeSourcePosition()); } public EncodedGraph(byte[] encoding, int startOffset, Object[] objects, NodeClass[] types, Assumptions assumptions, List inlinedMethods, - EconomicSet fields, boolean hasUnsafeAccess, boolean trackNodeSourcePosition) { + boolean hasUnsafeAccess, boolean trackNodeSourcePosition) { this.encoding = encoding; this.startOffset = startOffset; this.objects = objects; @@ -70,7 +66,6 @@ public EncodedGraph(byte[] encoding, int startOffset, Object[] objects, NodeClas this.assumptions = assumptions; this.inlinedMethods = inlinedMethods; this.trackNodeSourcePosition = trackNodeSourcePosition; - this.fields = fields; this.hasUnsafeAccess = hasUnsafeAccess; } @@ -110,10 +105,6 @@ public boolean trackNodeSourcePosition() { return trackNodeSourcePosition; } - public EconomicSet getFields() { - return fields; - } - public boolean hasUnsafeAccess() { return hasUnsafeAccess; } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedNode.java index 7bedd4f25f00..f9da728707db 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedNode.java @@ -42,8 +42,9 @@ public boolean verify() { return super.verify(); } + /* This method is final to ensure that it can be de-virtualized and inlined. */ @Override - public FixedNode asNode() { + public final FixedNode asFixedNode() { return this; } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedNodeInterface.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedNodeInterface.java index b89d4497ac26..0fc06896f530 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedNodeInterface.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedNodeInterface.java @@ -24,7 +24,9 @@ */ package org.graalvm.compiler.nodes; +/** + * See {@link ValueNodeInterface} for details about these node interfaces. + */ public interface FixedNodeInterface extends ValueNodeInterface { - @Override - FixedNode asNode(); + FixedNode asFixedNode(); } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedWithNextNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedWithNextNode.java index a47b6ba926b2..7c4803771fdc 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedWithNextNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedWithNextNode.java @@ -33,7 +33,7 @@ * successor. */ @NodeInfo -public abstract class FixedWithNextNode extends FixedNode { +public abstract class FixedWithNextNode extends FixedNode implements FixedWithNextNodeInterface { public static final NodeClass TYPE = NodeClass.create(FixedWithNextNode.class); @Successor protected FixedNode next; @@ -51,8 +51,9 @@ public FixedWithNextNode(NodeClass c, Stamp stamp) super(c, stamp); } + /* This method is final to ensure that it can be de-virtualized and inlined. */ @Override - public FixedWithNextNode asNode() { + public final FixedWithNextNode asFixedWithNextNode() { return this; } } diff --git a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeInterface.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedWithNextNodeInterface.java similarity index 78% rename from compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeInterface.java rename to compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedWithNextNodeInterface.java index 6ed0030589d4..184265475c42 100644 --- a/compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeInterface.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedWithNextNodeInterface.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,8 +22,11 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.compiler.graph; +package org.graalvm.compiler.nodes; -public interface NodeInterface { - Node asNode(); +/** + * See {@link ValueNodeInterface} for details about these node interfaces. + */ +public interface FixedWithNextNodeInterface extends FixedNodeInterface { + FixedWithNextNode asFixedWithNextNode(); } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java index 4a033b71f141..9134d04c84b0 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java @@ -34,6 +34,7 @@ import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -307,7 +308,7 @@ public ResolvedJavaMethod getMethod() { * latter has been subject to instrumentation. */ public boolean canProduceBytecodeFrame() { - return code != null && code.getCode() == code.getMethod().getCode(); + return code != null && Arrays.equals(code.getCode(), code.getMethod().getCode()); } public void addVirtualObjectMapping(EscapeObjectState virtualObject) { diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java index 7bf031683558..dfed035ef116 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java @@ -189,22 +189,26 @@ public GraphEncoder(Architecture architecture, DebugContext debug) { * Must be invoked before {@link #finishPrepare()} and {@link #encode}. */ public void prepare(StructuredGraph graph) { - objects.addObject(graph.getGuardsStage()); + addObject(graph.getGuardsStage()); for (Node node : graph.getNodes()) { NodeClass nodeClass = node.getNodeClass(); nodeClasses.addObject(nodeClass); - objects.addObject(node.getNodeSourcePosition()); + addObject(node.getNodeSourcePosition()); for (int i = 0; i < nodeClass.getData().getCount(); i++) { if (!nodeClass.getData().getType(i).isPrimitive()) { - objects.addObject(nodeClass.getData().get(node, i)); + addObject(nodeClass.getData().get(node, i)); } } if (node instanceof Invoke) { - objects.addObject(((Invoke) node).getContextType()); + addObject(((Invoke) node).getContextType()); } } } + protected void addObject(Object object) { + objects.addObject(object); + } + public void finishPrepare() { objectsArray = objects.encodeAll(new Object[objects.getLength()]); nodeClassesArray = nodeClasses.encodeAll(new NodeClass[nodeClasses.getLength()]); diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java index 0cb5688c0282..de002c0ce596 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java @@ -190,13 +190,13 @@ public void addDecision(Invokable invoke, boolean positive, String phase, Econom } MapCursor entries = calleeLog.leaves.getEntries(); while (entries.advance()) { - Invokable invokeFromCallee = entries.getKey(); + FixedNode invokeFromCallee = entries.getKey().asFixedNodeOrNull(); Callsite callsiteFromCallee = entries.getValue(); - if (invokeFromCallee.asFixedNode().isDeleted()) { + if (invokeFromCallee == null || invokeFromCallee.isDeleted()) { // Some invoke nodes could have been removed by optimizations. continue; } - Invokable inlinedInvokeFromCallee = (Invokable) replacements.get(invokeFromCallee.asFixedNode()); + Invokable inlinedInvokeFromCallee = (Invokable) replacements.get(invokeFromCallee); Callsite descendant = mapping.get(callsiteFromCallee); leaves.put(inlinedInvokeFromCallee, descendant); } @@ -219,13 +219,13 @@ public void addLog(UnmodifiableEconomicMap replacements, InliningLog } MapCursor entries = replacementLog.leaves.getEntries(); while (entries.advance()) { - Invokable replacementInvoke = entries.getKey(); + FixedNode replacementInvoke = entries.getKey().asFixedNodeOrNull(); Callsite replacementCallsite = entries.getValue(); - if (replacementInvoke.asFixedNode().isDeleted()) { + if (replacementInvoke == null || replacementInvoke.isDeleted()) { // Some invoke nodes could have been removed by optimizations. continue; } - Invokable invoke = (Invokable) replacements.get(replacementInvoke.asFixedNode()); + Invokable invoke = (Invokable) replacements.get(replacementInvoke); Callsite callsite = mapping.get(replacementCallsite); leaves.put(invoke, callsite); } @@ -247,10 +247,10 @@ public void replaceLog(UnmodifiableEconomicMap replacements, Inlinin copyTree(root, replacementLog.root, replacements, mapping); MapCursor replacementEntries = replacementLog.leaves.getEntries(); while (replacementEntries.advance()) { - Invokable replacementInvoke = replacementEntries.getKey(); + FixedNode replacementInvoke = replacementEntries.getKey().asFixedNodeOrNull(); Callsite replacementSite = replacementEntries.getValue(); - if (replacementInvoke.isAlive()) { - Invokable invoke = (Invokable) replacements.get((Node) replacementInvoke); + if (replacementInvoke != null && replacementInvoke.isAlive()) { + Invokable invoke = (Invokable) replacements.get(replacementInvoke); Callsite site = mapping.get(replacementSite); leaves.put(invoke, site); } @@ -261,7 +261,8 @@ private void copyTree(Callsite site, Callsite replacementSite, UnmodifiableEcono mapping.put(replacementSite, site); site.target = replacementSite.target; site.decisions.addAll(replacementSite.decisions); - site.invoke = replacementSite.invoke != null && replacementSite.invoke.isAlive() ? (Invokable) replacements.get(replacementSite.invoke.asFixedNode()) : null; + FixedNode replacementSiteInvoke = replacementSite.invoke != null ? replacementSite.invoke.asFixedNodeOrNull() : null; + site.invoke = replacementSiteInvoke != null && replacementSiteInvoke.isAlive() ? (Invokable) replacements.get(replacementSiteInvoke) : null; for (Callsite replacementChild : replacementSite.children) { Callsite child = new Callsite(site, null); site.children.add(child); @@ -435,13 +436,8 @@ public void setBci(int bci) { } @Override - public boolean isAlive() { - return false; - } - - @Override - public FixedNode asFixedNode() { - throw new UnsupportedOperationException("Parsed invokable is a placeholder, not a concrete node."); + public FixedNode asFixedNodeOrNull() { + return null; } @Override diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invokable.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invokable.java index 556fb494366e..97f0190f3700 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invokable.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invokable.java @@ -24,11 +24,12 @@ */ package org.graalvm.compiler.nodes; -import jdk.vm.ci.meta.ResolvedJavaMethod; import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; +import jdk.vm.ci.meta.ResolvedJavaMethod; + /** * A marker interface for nodes that represent calls to other methods. */ @@ -42,12 +43,13 @@ public interface Invokable extends DeoptBciSupplier { */ ResolvedJavaMethod getContextMethod(); - default boolean isAlive() { - return asFixedNode().isAlive(); + /** + * Returns the receiver cast to {@link FixedNode}, or null if this invokable is a placeholder. + */ + default FixedNode asFixedNodeOrNull() { + return this instanceof FixedNode ? (FixedNode) this : null; } - FixedNode asFixedNode(); - /** * Called on a {@link Invokable} node after it is registered with a graph. * @@ -73,15 +75,16 @@ default void updateInliningLogAfterRegister(StructuredGraph newGraph) { * updating logic by calling {@link InliningLog#openUpdateScope}. */ default void updateInliningLogAfterClone(Node other) { - if (GraalOptions.TraceInlining.getValue(asFixedNode().getOptions())) { + StructuredGraph graph = asFixedNodeOrNull().graph(); + if (GraalOptions.TraceInlining.getValue(graph.getOptions())) { // At this point, the invokable node was already added to the inlining log // in the call to updateInliningLogAfterRegister, so we need to remove it. - InliningLog log = asFixedNode().graph().getInliningLog(); + InliningLog log = graph.getInliningLog(); assert other instanceof Invokable; if (log.getUpdateScope() != null) { // InliningLog.UpdateScope determines how to update the log. log.getUpdateScope().accept((Invokable) other, this); - } else if (other.graph() == this.asFixedNode().graph()) { + } else if (other.graph() == graph) { // This node was cloned as part of duplication. // We need to add it as a sibling of the node other. assert log.containsLeafCallsite(this) : "Node " + this + " not contained in the log."; diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invoke.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invoke.java index 2fb76cfbc840..054e1f9978d0 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invoke.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invoke.java @@ -65,6 +65,10 @@ public boolean allowSubstitution() { void setNext(FixedNode x); + default boolean isAlive() { + return asFixedNode().isAlive(); + } + CallTargetNode callTarget(); Node predecessor(); diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java index d6b6dd778bc9..b45bee778cee 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java @@ -115,11 +115,6 @@ protected void afterClone(Node other) { updateInliningLogAfterClone(other); } - @Override - public FixedNode asFixedNode() { - return this; - } - @Override public CallTargetNode callTarget() { return callTarget; diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java index 642d5fd15c40..93067d8447e6 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java @@ -84,11 +84,6 @@ protected void afterClone(Node other) { updateInliningLogAfterClone(other); } - @Override - public FixedNode asFixedNode() { - return this; - } - @Override public CallTargetNode callTarget() { return callTarget; @@ -183,9 +178,12 @@ public Map getDebugProperties(Map map) { return debugProperties; } - @SuppressWarnings("try") public AbstractBeginNode killKillingBegin() { - AbstractBeginNode begin = next(); + return killKillingBegin(next()); + } + + @SuppressWarnings("try") + public AbstractBeginNode killKillingBegin(AbstractBeginNode begin) { if (begin instanceof KillingBeginNode) { try (DebugCloseable position = begin.withNodeSourcePosition()) { AbstractBeginNode newBegin = new BeginNode(); @@ -261,7 +259,19 @@ public InvokeNode replaceWithNonThrowing() { @Override public void simplify(SimplifierTool tool) { if (exceptionEdge() instanceof UnreachableBeginNode) { - replaceWithInvoke(); + AbstractBeginNode storedNext = next(); + InvokeNode replacement = replaceWithInvoke(); + if (graph().isAfterStage(StructuredGraph.StageFlag.FLOATING_READS)) { + if (!tool.allUsagesAvailable()) { + // we don't know about the usages - do nothing + return; + } + storedNext.replaceAtUsages(replacement, Memory); + } + // kill the killing begin + AbstractBeginNode newBegin = killKillingBegin(storedNext); + tool.addToWorkList(newBegin.next()); + tool.addToWorkList(newBegin); } } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/KillingBeginNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/KillingBeginNode.java index f02b7a832908..f804e2b8cdb8 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/KillingBeginNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/KillingBeginNode.java @@ -29,12 +29,12 @@ import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodeinfo.InputType; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.memory.SingleMemoryKill; -import org.graalvm.compiler.nodes.spi.Simplifiable; -import org.graalvm.compiler.nodes.spi.SimplifierTool; +import org.graalvm.compiler.nodes.spi.Canonicalizable; +import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.word.LocationIdentity; /** @@ -44,7 +44,7 @@ * @see WithExceptionNode for more details */ @NodeInfo(allowedUsageTypes = {Memory}, cycles = CYCLES_0, size = SIZE_0) -public final class KillingBeginNode extends AbstractBeginNode implements SingleMemoryKill, Simplifiable { +public final class KillingBeginNode extends AbstractBeginNode implements SingleMemoryKill, Canonicalizable { public static final NodeClass TYPE = NodeClass.create(KillingBeginNode.class); protected LocationIdentity locationIdentity; @@ -73,28 +73,23 @@ public LocationIdentity getKilledLocationIdentity() { } @Override - public void simplify(SimplifierTool tool) { - if (predecessor() instanceof FixedWithNextNode && predecessor() instanceof SingleMemoryKill) { - SingleMemoryKill predecessor = (SingleMemoryKill) predecessor(); - if (getKilledLocationIdentity().equals(predecessor.getKilledLocationIdentity())) { - // This killing begin node can be removed. - tool.addToWorkList(next()); - graph().removeFixed(this); - } - } + public void prepareDelete() { + GraalError.guarantee(graph().isBeforeStage(StructuredGraph.StageFlag.FLOATING_READS) || !hasUsagesOfType(Memory), "Cannot delete %s with memory usages %s", this, usages().snapshot()); + super.prepareDelete(); } @Override - public void prepareDelete() { - GraalError.guarantee(predecessor() instanceof SingleMemoryKill, "Cannot delete %s as its predecessor %s is not a SingleMemoryKill", this, predecessor()); - GraalError.guarantee(getKilledLocationIdentity().equals(((SingleMemoryKill) predecessor()).getKilledLocationIdentity()), - "Cannot delete %s as its predecessor %s kills a different location (%s vs. %s)", this, predecessor(), getKilledLocationIdentity(), - ((SingleMemoryKill) predecessor()).getKilledLocationIdentity()); - if (hasUsages()) { - // Memory edges are moved to the predecessor. - replaceAtUsages(predecessor(), InputType.Memory); + public Node canonical(CanonicalizerTool tool) { + if (graph().isBeforeStage(StructuredGraph.StageFlag.FLOATING_READS)) { + if (!(predecessor() instanceof WithExceptionNode)) { + return new BeginNode(); + } + } else { + // after floating read - we need to check the memory graph + if (tool.allUsagesAvailable() && !(predecessor() instanceof WithExceptionNode) && !hasUsagesOfType(Memory)) { + return new BeginNode(); + } } - // The guards are moved up to the preceding begin node. - super.prepareDelete(); + return this; } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java index 196531c2b868..a0c6bb5b1daa 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java @@ -36,7 +36,6 @@ import org.graalvm.compiler.graph.iterators.NodeIterable; import org.graalvm.compiler.nodeinfo.InputType; import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.ProfileData.LoopFrequencyData; import org.graalvm.compiler.nodes.StructuredGraph.FrameStateVerificationFeature; import org.graalvm.compiler.nodes.calc.AddNode; import org.graalvm.compiler.nodes.extended.GuardingNode; @@ -53,7 +52,6 @@ public final class LoopBeginNode extends AbstractMergeNode implements IterableNodeType, LIRLowerable { public static final NodeClass TYPE = NodeClass.create(LoopBeginNode.class); - private LoopFrequencyData profileData; protected double loopOrigFrequency; protected int nextEndIndex; protected int unswitches; @@ -139,7 +137,6 @@ public boolean isProtectedNonOverflowingUnsigned() { public LoopBeginNode() { super(TYPE); - profileData = LoopFrequencyData.DEFAULT; loopOrigFrequency = 1; unswitches = 0; splits = 0; @@ -262,18 +259,6 @@ public void setLoopOrigFrequency(double loopOrigFrequency) { this.loopOrigFrequency = loopOrigFrequency; } - public LoopFrequencyData profileData() { - return profileData; - } - - public double loopFrequency() { - return profileData.getLoopFrequency(); - } - - public void setLoopFrequency(LoopFrequencyData newProfileData) { - this.profileData = newProfileData; - } - /** * Returns the unordered set of {@link LoopEndNode} that correspond to back-edges for * this loop. The order of the back-edges is unspecified, if you need to get an ordering diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java index 7b86b3f80b16..dc695ec91b4e 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java @@ -33,6 +33,7 @@ import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.TypeReference; import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.Node.NodeIntrinsicFactory; import org.graalvm.compiler.graph.NodeClass; @@ -125,13 +126,31 @@ public static ValueNode create(ValueNode object, ValueNode guard) { return new PiNode(object, stamp, guard); } - public static boolean intrinsify(GraphBuilderContext b, ValueNode object, ValueNode guard) { - Stamp stamp = AbstractPointerStamp.pointerNonNull(object.stamp(NodeView.DEFAULT)); - ValueNode value = canonical(object, stamp, (GuardingNode) guard, null); + public enum IntrinsifyOp { + NON_NULL, + POSITIVE_INT + } + + public static boolean intrinsify(GraphBuilderContext b, ValueNode input, ValueNode guard, IntrinsifyOp intrinsifyOp) { + Stamp piStamp; + JavaKind pushKind; + switch (intrinsifyOp) { + case NON_NULL: + piStamp = AbstractPointerStamp.pointerNonNull(input.stamp(NodeView.DEFAULT)); + pushKind = JavaKind.Object; + break; + case POSITIVE_INT: + piStamp = StampFactory.positiveInt(); + pushKind = JavaKind.Int; + break; + default: + throw GraalError.shouldNotReachHere(); + } + ValueNode value = canonical(input, piStamp, (GuardingNode) guard, null); if (value == null) { - value = new PiNode(object, stamp, guard); + value = new PiNode(input, piStamp, guard); } - b.push(JavaKind.Object, b.append(value)); + b.push(pushKind, b.append(value)); return true; } @@ -146,6 +165,17 @@ public static boolean intrinsify(GraphBuilderContext b, ValueNode object, Resolv return true; } + /** + * A stamp expressing the property that is proved by the {@linkplain #getGuard() guard}, but not + * more. + *

+ * + * For example, if the guard proves a property {@code x >= 0} on an {@code int} value, then the + * {@link #piStamp()} should be {@link StampFactory#positiveInt()}. If the input value's stamp + * is constrained, e.g., {@code [-100 - 100]}, then this pi's overall {@link #stamp(NodeView)} + * will be {@code [0 - 100]}, computed as the join of the {@link #piStamp()} and the input's + * stamp. + */ public final Stamp piStamp() { return piStamp; } @@ -205,7 +235,14 @@ public static ValueNode canonical(ValueNode object, Stamp piStamp, GuardingNode for (Node n : guard.asNode().usages()) { if (n instanceof PiNode && n != self) { PiNode otherPi = (PiNode) n; - assert otherPi.guard == guard; + if (otherPi.guard != guard) { + assert otherPi.object() == guard; + /* + * The otherPi is unrelated because it uses this.guard as object but not as + * guard. + */ + continue; + } if (otherPi.object() == self || otherPi.object() == object) { // Check if other pi's stamp is more precise Stamp joinedStamp = piStamp.improveWith(otherPi.piStamp()); @@ -231,6 +268,15 @@ public Node canonical(CanonicalizerTool tool) { if (value != null) { return value; } + if (tool.allUsagesAvailable()) { + for (Node usage : usages()) { + if (!(usage instanceof VirtualState)) { + return this; + } + } + // Only state usages: for them a more precise stamp does not matter. + return object; + } return this; } @@ -269,19 +315,44 @@ public static Class asNonNullObject(Object object) { @NodeIntrinsic(PiNode.Placeholder.class) public static native Object piCastToSnippetReplaceeStamp(Object object); + /** + * Changes the stamp of a primitive value and ensures the newly stamped value is positive and + * does not float above a given guard. + * + * @param value an arbitrary {@code int} value + * @param guard a node proving that {@code value >= 0} holds at some point in the graph + * + * @return the {@code value} with its stamp clamped to exclude negative values, guarded by + * {@code guard} + */ + public static int piCastPositive(int value, GuardingNode guard) { + return intrinsified(value, guard, IntrinsifyOp.POSITIVE_INT); + } + + @NodeIntrinsic + private static native int intrinsified(int value, GuardingNode guard, @ConstantNodeParameter IntrinsifyOp intrinsifyOp); + /** * Changes the stamp of an object and ensures the newly stamped value is non-null and does not * float above a given guard. */ + public static Object piCastNonNull(Object object, GuardingNode guard) { + return intrinsified(object, guard, IntrinsifyOp.NON_NULL); + } + @NodeIntrinsic - public static native Object piCastNonNull(Object object, GuardingNode guard); + private static native Object intrinsified(Object object, GuardingNode guard, @ConstantNodeParameter IntrinsifyOp intrinsifyOp); /** * Changes the stamp of an object and ensures the newly stamped value is non-null and does not * float above a given guard. */ + public static Class piCastNonNullClass(Class type, GuardingNode guard) { + return intrinsified(type, guard, IntrinsifyOp.NON_NULL); + } + @NodeIntrinsic - public static native Class piCastNonNullClass(Class type, GuardingNode guard); + private static native Class intrinsified(Class object, GuardingNode guard, @ConstantNodeParameter IntrinsifyOp intrinsifyOp); /** * Changes the stamp of an object to represent a given type and to indicate that the object is diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PluginReplacementInterface.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PluginReplacementInterface.java new file mode 100644 index 000000000000..78b9a1c0f502 --- /dev/null +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PluginReplacementInterface.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.nodes; + +import org.graalvm.compiler.nodes.graphbuilderconf.GeneratedPluginInjectionProvider; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; + +/** + * Interface for nodes responsible for {@linkplain GraphBuilderContext#shouldDeferPlugin deferring} + * {@linkplain org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin invocation plugin} + * application. + */ +public interface PluginReplacementInterface extends FixedNodeInterface { + /** + * Replaces this node by applying the stored plugin. + */ + boolean replace(GraphBuilderContext b, GeneratedPluginInjectionProvider injection); +} diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PluginReplacementNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PluginReplacementNode.java index d861cbb6519d..72789b34b98a 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PluginReplacementNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PluginReplacementNode.java @@ -37,7 +37,7 @@ import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; @NodeInfo(nameTemplate = "PluginReplacement/{p#pluginName}", cycles = NodeCycles.CYCLES_IGNORED, size = NodeSize.SIZE_IGNORED) -public final class PluginReplacementNode extends FixedWithNextNode { +public final class PluginReplacementNode extends FixedWithNextNode implements PluginReplacementInterface { public static final NodeClass TYPE = NodeClass.create(PluginReplacementNode.class); @Input protected NodeInputList args; @@ -51,6 +51,7 @@ public PluginReplacementNode(Stamp stamp, ValueNode[] args, ReplacementFunction this.pluginName = pluginName; } + @Override public boolean replace(GraphBuilderContext b, GeneratedPluginInjectionProvider injection) { return function.replace(b, injection, stamp, args); } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PluginReplacementWithExceptionNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PluginReplacementWithExceptionNode.java new file mode 100644 index 000000000000..f08352c41b92 --- /dev/null +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PluginReplacementWithExceptionNode.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.nodes; + +import java.util.Map; + +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.NodeInputList; +import org.graalvm.compiler.nodeinfo.NodeCycles; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodeinfo.NodeSize; +import org.graalvm.compiler.nodeinfo.Verbosity; +import org.graalvm.compiler.nodes.graphbuilderconf.GeneratedPluginInjectionProvider; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; + +@NodeInfo(nameTemplate = "PluginReplacementWithException/{p#pluginName}", cycles = NodeCycles.CYCLES_IGNORED, size = NodeSize.SIZE_IGNORED) +public final class PluginReplacementWithExceptionNode extends WithExceptionNode implements PluginReplacementInterface { + public static final NodeClass TYPE = NodeClass.create(PluginReplacementWithExceptionNode.class); + + @Input protected NodeInputList args; + private final ReplacementWithExceptionFunction function; + private final String pluginName; + + public PluginReplacementWithExceptionNode(Stamp stamp, ValueNode[] args, ReplacementWithExceptionFunction function, String pluginName) { + super(TYPE, stamp); + this.args = new NodeInputList<>(this, args); + this.function = function; + this.pluginName = pluginName; + } + + @Override + public boolean replace(GraphBuilderContext b, GeneratedPluginInjectionProvider injection) { + return function.replace(b, injection, stamp, args); + } + + public interface ReplacementWithExceptionFunction { + boolean replace(GraphBuilderContext b, GeneratedPluginInjectionProvider injection, Stamp stamp, NodeInputList args); + } + + @Override + public String toString(Verbosity verbosity) { + if (verbosity == Verbosity.Short) { + return super.toString(verbosity) + "/" + pluginName; + } + return super.toString(verbosity); + } + + @Override + public Map getDebugProperties(Map map) { + map.put("name", pluginName); + return super.getDebugProperties(map); + } +} diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ProfileData.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ProfileData.java index 966200aa5ea1..d7f7977f1aad 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ProfileData.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ProfileData.java @@ -86,6 +86,7 @@ public ProfileSource combine(ProfileSource other) { public static boolean isTrusted(ProfileSource source) { return source == INJECTED || source == PROFILED; } + } public ProfileSource getProfileSource() { diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java index 100cae11097a..4e0905ba1a90 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java @@ -39,7 +39,6 @@ import java.util.stream.Collectors; import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; import org.graalvm.collections.Equivalence; import org.graalvm.collections.UnmodifiableEconomicMap; import org.graalvm.compiler.api.replacements.MethodSubstitution; @@ -71,7 +70,6 @@ import jdk.vm.ci.meta.DefaultProfilingInfo; import jdk.vm.ci.meta.JavaMethod; import jdk.vm.ci.meta.ProfilingInfo; -import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.SpeculationLog; import jdk.vm.ci.meta.TriState; @@ -133,6 +131,10 @@ public boolean areDeoptsFixed() { public boolean requiresValueProxies() { return this != AFTER_FSA; } + + public boolean reachedGuardsStage(GuardsStage stage) { + return this.ordinal() >= stage.ordinal(); + } } /** @@ -456,11 +458,6 @@ boolean implies(FrameStateVerificationFeature feature) { */ private final List methods; - /** - * Records the fields that were accessed while constructing this graph. - */ - private EconomicSet fields = null; - private enum UnsafeAccessState { NO_ACCESS, HAS_ACCESS, @@ -720,9 +717,6 @@ private StructuredGraph copy(String newName, ResolvedJavaMethod rootMethodForCop copy.setGuardsStage(getGuardsStage()); copy.stageFlags = EnumSet.copyOf(stageFlags); copy.trackNodeSourcePosition = trackNodeSourcePositionForCopy; - if (fields != null) { - copy.fields = createFieldSet(fields); - } EconomicMap replacements = EconomicMap.create(Equivalence.IDENTITY); replacements.put(start, copy.start); UnmodifiableEconomicMap duplicates; @@ -1107,15 +1101,6 @@ private boolean checkFrameStatesAgainstInlinedMethods() { return true; } - private static EconomicSet createFieldSet(EconomicSet init) { - // Multiple ResolvedJavaField objects can represent the same field so they - // need to be compared with equals(). - if (init != null) { - return EconomicSet.create(Equivalence.DEFAULT, init); - } - return EconomicSet.create(Equivalence.DEFAULT); - } - /** * Gets an unmodifiable view of the methods that were inlined while constructing this graph. */ @@ -1151,41 +1136,6 @@ public void updateMethods(StructuredGraph other) { } } - /** - * Gets an unmodifiable view of the fields that were accessed while constructing this graph. - * - * @return {@code null} if no field accesses were recorded - */ - public EconomicSet getFields() { - return fields; - } - - /** - * Records that {@code field} was accessed in this graph. - */ - public void recordField(ResolvedJavaField field) { - assert GraalOptions.GeneratePIC.getValue(getOptions()); - if (this.fields == null) { - this.fields = createFieldSet(null); - } - fields.add(field); - } - - /** - * Updates the {@linkplain #getFields() fields} of this graph with the accessed fields of - * another graph. - */ - public void updateFields(StructuredGraph other) { - assert this != other; - assert GraalOptions.GeneratePIC.getValue(getOptions()); - if (other.fields != null) { - if (this.fields == null) { - this.fields = createFieldSet(null); - } - this.fields.addAll(other.fields); - } - } - /** * Gets the input bytecode {@linkplain ResolvedJavaMethod#getCodeSize() size} from which this * graph is constructed. This ignores how many bytecodes in each constituent method are actually diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNode.java index adc74bf7db95..3d611b16b69a 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNode.java @@ -25,7 +25,6 @@ package org.graalvm.compiler.nodes; import java.util.Iterator; -import java.util.function.Predicate; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.Node; @@ -189,11 +188,16 @@ public final SerializableConstant asSerializableConstant() { } } + /* This method is final to ensure that it can be de-virtualized and inlined. */ @Override - public ValueNode asNode() { + public final ValueNode asNode() { return this; } + protected void updateUsagesInterface(ValueNodeInterface oldInput, ValueNodeInterface newInput) { + updateUsages(oldInput == null ? null : oldInput.asNode(), newInput == null ? null : newInput.asNode()); + } + @Override public boolean isAllowedUsageType(InputType type) { if (getStackKind() != JavaKind.Void && type == InputType.Value) { @@ -220,18 +224,7 @@ public boolean hasUsagesOtherThan(ValueNode node, NodeValueMap nodeValueMap) { } @Override - protected void replaceAtUsages(Node other, Predicate filter, Node toBeDeleted) { - super.replaceAtUsages(other, filter, toBeDeleted); - assert checkReplaceAtUsagesInvariants(other); - } - - @Override - protected void replaceAtAllUsages(Node other, Node toBeDeleted) { - super.replaceAtAllUsages(other, toBeDeleted); - assert checkReplaceAtUsagesInvariants(other); - } - - private boolean checkReplaceAtUsagesInvariants(Node other) { + protected boolean checkReplaceAtUsagesInvariants(Node other) { assert other == null || other instanceof ValueNode; if (this.hasUsages() && !this.stamp(NodeView.DEFAULT).isEmpty() && !(other instanceof PhiNode) && other != null) { Stamp thisStamp = stamp(NodeView.DEFAULT); diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNodeInterface.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNodeInterface.java index 2452e2d43449..5cf79f509cf7 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNodeInterface.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNodeInterface.java @@ -24,9 +24,25 @@ */ package org.graalvm.compiler.nodes; -import org.graalvm.compiler.graph.NodeInterface; - -public interface ValueNodeInterface extends NodeInterface { - @Override +/** + * When Graal {@link ValueNode} classes implement interfaces, it is frequently necessary to convert + * from an interface type back to a Node. This could be easily done using a cast, but casts come + * with a run time cost. Using a conversion method, which is implemented once on + * {@link ValueNode#asNode()}, avoids a cast. But it is faster only as long as the implementation + * method can be inlined. Therefore, it is important that only one implementation of the interface + * method exists, so that either single-implementor speculation (for JIT compilation) or static + * analysis results (for AOT compilation) allow the one implementation to be inlined. + * + * Subinterfaces like {@link FixedNodeInterface} provide a conversion method that has a more precise + * return type. Note that these sub-interfaces use a different method name like + * {@link FixedNodeInterface#asFixedNode()}, which then have another single implementation without a + * cast in {@link FixedNode#asFixedNode()}. + */ +public interface ValueNodeInterface { + /* + * This method is called `asNode` and not `asValueNode` partly for historic reasons, because + * originally the interface was called just `NodeInterface`. But since there are so many + * callers, we also want to keep the call sites as short as possible. + */ ValueNode asNode(); } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/WithExceptionNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/WithExceptionNode.java index eee80b7218c2..7a9b94683406 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/WithExceptionNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/WithExceptionNode.java @@ -90,8 +90,10 @@ public void setExceptionEdge(AbstractBeginNode x) { public void killExceptionEdge() { AbstractBeginNode edge = exceptionEdge(); - setExceptionEdge(null); - GraphUtil.killCFG(edge); + if (edge != null) { + setExceptionEdge(null); + GraphUtil.killCFG(edge); + } } @Override diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java index 0b58f353aadf..72eba3553023 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java @@ -24,7 +24,6 @@ */ package org.graalvm.compiler.nodes.calc; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1; import org.graalvm.compiler.core.common.PermanentBailoutException; @@ -223,7 +222,7 @@ protected LogicNode canonicalizeSymmetricConstant(ConstantReflectionProvider con } if (isConstantConversionSupported(convert, view, smallestCompareWidth)) { - ConstantNode newConstant = canonicalConvertConstant(constantReflection, metaAccess, options, condition, convert, constant, view); + ConstantNode newConstant = canonicalConvertConstant(constantReflection, metaAccess, condition, convert, constant, view); if (newConstant != null) { if (mirrored) { return duplicateModified(newConstant, convert.getValue(), unorderedIsTrue, view); @@ -253,15 +252,11 @@ private static boolean isConstantConversionSupported(ConvertNode convert, NodeVi return supported; } - private static ConstantNode canonicalConvertConstant(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, CanonicalCondition condition, - ConvertNode convert, Constant constant, NodeView view) { + private static ConstantNode canonicalConvertConstant(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, CanonicalCondition condition, ConvertNode convert, + Constant constant, NodeView view) { if (convert.preservesOrder(condition, constant, constantReflection)) { Constant reverseConverted = convert.reverse(constant, constantReflection); if (reverseConverted != null && convert.convert(reverseConverted, constantReflection).equals(constant)) { - if (GeneratePIC.getValue(options)) { - // We always want uncompressed constants - return null; - } return ConstantNode.forConstant(convert.getValue().stamp(view), reverseConverted, metaAccess); } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatingNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatingNode.java index 8d348bd20fc9..13ca1b0bf764 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatingNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatingNode.java @@ -37,9 +37,4 @@ public abstract class FloatingNode extends ValueNode implements ValueNumberable public FloatingNode(NodeClass c, Stamp stamp) { super(c, stamp); } - - @Override - public FloatingNode asNode() { - return this; - } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerConvertNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerConvertNode.java index 3a030a21841f..40ac5dc7342d 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerConvertNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerConvertNode.java @@ -28,11 +28,11 @@ import org.graalvm.compiler.core.common.type.ArithmeticOpTable; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp; +import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.PrimitiveStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ArithmeticOperation; import org.graalvm.compiler.nodes.ConstantNode; @@ -40,6 +40,7 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable; +import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodes.spi.StampInverter; import jdk.vm.ci.meta.Constant; @@ -119,14 +120,24 @@ public static ValueNode convert(ValueNode input, Stamp stamp, NodeView view) { } public static ValueNode convert(ValueNode input, Stamp stamp, StructuredGraph graph, NodeView view) { - return convert(input, stamp, false, graph, view); + return convert(input, stamp, false, graph, view, true); } public static ValueNode convert(ValueNode input, Stamp stamp, boolean zeroExtend, StructuredGraph graph, NodeView view) { - ValueNode convert = convert(input, stamp, zeroExtend, view); - if (!convert.isAlive()) { - assert !convert.isDeleted(); - convert = graph.addOrUniqueWithInputs(convert); + return convert(input, stamp, zeroExtend, graph, view, true); + } + + public static ValueNode convert(ValueNode input, Stamp stamp, boolean zeroExtend, StructuredGraph graph, NodeView view, boolean gvn) { + ValueNode convert = convert(input, stamp, zeroExtend, view, gvn); + if (gvn) { + if (!convert.isAlive()) { + assert !convert.isDeleted(); + convert = graph.addOrUniqueWithInputs(convert); + } + } else { + GraalError.guarantee(!convert.isAlive(), "Convert must not GVN"); + GraalError.guarantee(!convert.isDeleted(), "Convert must not GVN"); + convert = graph.addWithoutUniqueWithInputs(convert); } return convert; } @@ -145,20 +156,32 @@ public static ValueNode convertUnsigned(ValueNode input, Stamp stamp, Structured } public static ValueNode convert(ValueNode input, Stamp stamp, boolean zeroExtend, NodeView view) { + return convert(input, stamp, zeroExtend, view, true); + } + + private static ValueNode convert(ValueNode input, Stamp stamp, boolean zeroExtend, NodeView view, boolean gvn) { IntegerStamp fromStamp = (IntegerStamp) input.stamp(view); IntegerStamp toStamp = (IntegerStamp) stamp; ValueNode result; - if (toStamp.getBits() == fromStamp.getBits()) { + if (gvn && toStamp.getBits() == fromStamp.getBits()) { result = input; } else if (toStamp.getBits() < fromStamp.getBits()) { result = new NarrowNode(input, fromStamp.getBits(), toStamp.getBits()); } else if (zeroExtend) { // toStamp.getBits() > fromStamp.getBits() - result = ZeroExtendNode.create(input, toStamp.getBits(), view); + if (gvn) { + result = ZeroExtendNode.create(input, toStamp.getBits(), view); + } else { + result = new ZeroExtendNode(input, toStamp.getBits()); + } } else { // toStamp.getBits() > fromStamp.getBits() - result = SignExtendNode.create(input, toStamp.getBits(), view); + if (gvn) { + result = SignExtendNode.create(input, toStamp.getBits(), view); + } else { + result = new SignExtendNode(input, toStamp.getBits()); + } } IntegerStamp resultStamp = (IntegerStamp) result.stamp(view); diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerTestNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerTestNode.java index b50dedbb1eb9..5bb1dc835bce 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerTestNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerTestNode.java @@ -30,14 +30,14 @@ import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.Canonicalizable.BinaryCommutative; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.BinaryOpLogicNode; import org.graalvm.compiler.nodes.LogicConstantNode; import org.graalvm.compiler.nodes.LogicNode; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.Canonicalizable.BinaryCommutative; +import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import jdk.vm.ci.meta.TriState; diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/MulNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/MulNode.java index 46e6137b0aac..0ac7500ea8e8 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/MulNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/MulNode.java @@ -32,13 +32,13 @@ import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.Canonicalizable.BinaryCommutative; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.Canonicalizable.BinaryCommutative; +import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import jdk.vm.ci.code.CodeUtil; @@ -90,6 +90,12 @@ public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode for // if this fails we only swap return new MulNode(forY, forX); } + + // convert "(-a)*(-b)" into "a*b" + if (forX instanceof NegateNode && forY instanceof NegateNode) { + return new MulNode(((NegateNode) forX).getValue(), ((NegateNode) forY).getValue()).maybeCommuteInputs(); + } + BinaryOp op = getOp(forX, forY); NodeView view = NodeView.from(tool); return canonical(this, op, stamp(view), forX, forY, view); diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RightShiftNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RightShiftNode.java index 572b30db7277..9294d4e03166 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RightShiftNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RightShiftNode.java @@ -32,12 +32,12 @@ import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import jdk.vm.ci.code.CodeUtil; @@ -163,7 +163,14 @@ public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool @Override public boolean isNarrowable(int resultBits) { - if (super.isNarrowable(resultBits)) { + /* + * Note that inserting a narrow before this node can change the input's stamp, as it can + * cause a preceding (Zero|Sign)ExtendNode to be canonicalized away. + * + * Therefore, since the scalar shift on the underlying hardware will be on either a 32 or 64 + * bit operation, if resultBits < Integer.SIZE, the input to the shift cannot be narrowed. + */ + if (resultBits >= Integer.SIZE && super.isNarrowable(resultBits)) { /* * For signed right shifts, the narrow can be done before the shift if the cut off bits * are all equal to the sign bit of the input. That's equivalent to the condition that diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ShiftNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ShiftNode.java index a4642bda8761..90ee93522cb1 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ShiftNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ShiftNode.java @@ -33,13 +33,13 @@ import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ArithmeticOperation; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable; +import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.meta.JavaConstant; @@ -107,7 +107,7 @@ public int getShiftAmountMask() { @Override public boolean isNarrowable(int resultBits) { assert CodeUtil.isPowerOf2(resultBits); - int narrowMask = resultBits - 1; + int narrowMask = resultBits <= 32 ? Integer.SIZE - 1 : Long.SIZE - 1; int wideMask = getShiftAmountMask(); assert (wideMask & narrowMask) == narrowMask : String.format("wideMask %x should be wider than narrowMask %x", wideMask, narrowMask); diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedDivNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedDivNode.java index 633a25f7dadb..e9b43c216697 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedDivNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedDivNode.java @@ -28,12 +28,13 @@ import org.graalvm.compiler.core.common.type.PrimitiveStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.extended.GuardingNode; +import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; @@ -67,6 +68,16 @@ public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode for return canonical(this, forX, forY, getZeroCheck(), view); } + /** + * This is used as a hook to allow AArch64IntegerArithmeticSnippets's SafeSignedDivNode to be + * created during canonicalization. + */ + protected SignedDivNode createWithInputs(ValueNode forX, ValueNode forY, GuardingNode forZeroCheck, FrameState forStateBefore) { + SignedDivNode sd = new SignedDivNode(forX, forY, forZeroCheck); + sd.stateBefore = forStateBefore; + return sd; + } + public static ValueNode canonical(SignedDivNode self, ValueNode forX, ValueNode forY, GuardingNode zeroCheck, NodeView view) { Stamp predictedStamp = IntegerStamp.OPS.getDiv().foldStamp(forX.stamp(NodeView.DEFAULT), forY.stamp(NodeView.DEFAULT)); Stamp stamp = self != null ? self.stamp(view) : predictedStamp; @@ -92,9 +103,10 @@ public static ValueNode canonical(SignedDivNode self, ValueNode forX, ValueNode SignedRemNode integerRemNode = (SignedRemNode) integerSubNode.getY(); if (integerSubNode.stamp(view).isCompatible(stamp) && integerRemNode.stamp(view).isCompatible(stamp) && integerSubNode.getX() == integerRemNode.getX() && forY == integerRemNode.getY()) { - SignedDivNode sd = new SignedDivNode(integerSubNode.getX(), forY, zeroCheck); - sd.stateBefore = self != null ? self.stateBefore : null; - return sd; + if (self != null) { + return self.createWithInputs(integerSubNode.getX(), forY, zeroCheck, self.stateBefore); + } + return new SignedDivNode(integerSubNode.getX(), forY, zeroCheck); } } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java index 38c462072b57..2f23d2dc93e0 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java @@ -28,12 +28,12 @@ import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.extended.GuardingNode; +import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; @@ -70,6 +70,14 @@ public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode for return canonical(this, forX, forY, getZeroCheck(), stamp(view), view, tool); } + /** + * This is used as a hook to allow AArch64IntegerArithmeticSnippets's SafeSignedRemNode to be + * created during canonicalization. + */ + protected SignedRemNode createWithInputs(ValueNode forX, ValueNode forY, GuardingNode forZeroCheck) { + return new SignedRemNode(forX, forY, forZeroCheck); + } + private static ValueNode canonical(SignedRemNode self, ValueNode forX, ValueNode forY, GuardingNode zeroCheck, Stamp stamp, NodeView view, CanonicalizerTool tool) { if (forX.isConstant() && forY.isConstant()) { long y = forY.asJavaConstant().asLong(); @@ -114,6 +122,9 @@ private static ValueNode canonical(SignedRemNode self, ValueNode forX, ValueNode if (self != null && self.x == forX && self.y == forY) { return self; } else { + if (self != null) { + return self.createWithInputs(forX, forY, zeroCheck); + } return new SignedRemNode(forX, forY, zeroCheck); } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnsignedRightShiftNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnsignedRightShiftNode.java index 7e2e0456945f..df0d7f921e88 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnsignedRightShiftNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnsignedRightShiftNode.java @@ -32,12 +32,12 @@ import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import jdk.vm.ci.code.CodeUtil; @@ -146,13 +146,20 @@ public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool @Override public boolean isNarrowable(int resultBits) { - if (super.isNarrowable(resultBits)) { + /* + * Note that inserting a narrow before this node can change the input's stamp, as it can + * cause a preceding (Zero|Sign)ExtendNode to be canonicalized away. + * + * Therefore, since the scalar shift on the underlying hardware will be on either a 32 or 64 + * bit operation, if resultBits < Integer.SIZE, the input to the shift cannot be narrowed. + */ + if (resultBits >= Integer.SIZE && super.isNarrowable(resultBits)) { /* * For unsigned right shifts, the narrow can be done before the shift if the cut off * bits are all zero. */ IntegerStamp inputStamp = (IntegerStamp) getX().stamp(NodeView.DEFAULT); - return (inputStamp.upMask() & ~(resultBits - 1)) == 0; + return (inputStamp.upMask() & ~(CodeUtil.mask(resultBits))) == 0; } else { return false; } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java index d91d2d74821b..f75f0a7b367c 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java @@ -39,6 +39,7 @@ import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.LoopEndNode; import org.graalvm.compiler.nodes.ProfileData.BranchProbabilityData; +import org.graalvm.compiler.nodes.ProfileData.ProfileSource; import org.graalvm.compiler.nodes.WithExceptionNode; import org.graalvm.compiler.nodes.memory.MultiMemoryKill; import org.graalvm.compiler.nodes.memory.SingleMemoryKill; @@ -51,7 +52,8 @@ public final class Block extends AbstractBlockBase { protected FixedNode endNode; - protected double relativeFrequency; + protected double relativeFrequency = -1D; + protected ProfileSource frequencySource; private Loop loop; protected Block postdominator; @@ -192,7 +194,13 @@ public String toString() { public String toString(Verbosity verbosity) { StringBuilder sb = new StringBuilder(); sb.append('B').append(id); - if (verbosity != Verbosity.Id) { + if (verbosity == Verbosity.Name) { + sb.append("{"); + sb.append(getBeginNode()); + sb.append("->"); + sb.append(getEndNode()); + sb.append("}"); + } else if (verbosity != Verbosity.Id) { if (isLoopHeader()) { sb.append(" lh"); } @@ -299,10 +307,18 @@ public double getRelativeFrequency() { } public void setRelativeFrequency(double relativeFrequency) { - assert relativeFrequency >= 0 && Double.isFinite(relativeFrequency); + assert relativeFrequency >= 0 && Double.isFinite(relativeFrequency) : "Relative Frequency=" + relativeFrequency; this.relativeFrequency = relativeFrequency; } + public void setFrequencySource(ProfileSource frequencySource) { + this.frequencySource = frequencySource; + } + + public ProfileSource getFrequencySource() { + return frequencySource; + } + @Override public Block getDominator(int distance) { Block result = this; diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java index ba9ba7b1b89e..ce69e5e45147 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java @@ -30,30 +30,48 @@ import java.util.Arrays; import java.util.BitSet; import java.util.List; +import java.util.function.Consumer; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph; import org.graalvm.compiler.core.common.cfg.CFGVerifier; import org.graalvm.compiler.core.common.cfg.Loop; +import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeMap; import org.graalvm.compiler.graph.iterators.NodeIterable; import org.graalvm.compiler.nodes.AbstractBeginNode; -import org.graalvm.compiler.nodes.AbstractEndNode; -import org.graalvm.compiler.nodes.AbstractMergeNode; import org.graalvm.compiler.nodes.ControlSinkNode; import org.graalvm.compiler.nodes.ControlSplitNode; -import org.graalvm.compiler.nodes.EndNode; +import org.graalvm.compiler.nodes.DeoptimizeNode; import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.FixedWithNextNode; -import org.graalvm.compiler.nodes.IfNode; import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.LoopEndNode; import org.graalvm.compiler.nodes.LoopExitNode; +import org.graalvm.compiler.nodes.ProfileData.LoopFrequencyData; +import org.graalvm.compiler.nodes.ProfileData.ProfileSource; +import org.graalvm.compiler.nodes.ReturnNode; import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionKey; +import org.graalvm.compiler.options.OptionType; public final class ControlFlowGraph implements AbstractControlFlowGraph { + + public static class CFGOptions { + //@formatter:off + @Option(help = "Debug flag to dump loop frequency differences computed based on loop end or exit nodes." + + "If the frequencies diverge a lot, this may indicate missing profiles on control flow" + + "inside the loop body.", type = OptionType.Debug) + public static final OptionKey DumpEndVersusExitLoopFrequencies = new OptionKey<>(false); + @Option(help = "Scaling factor of frequency difference computed based on loop ends or exits", type = OptionType.Debug) + public static final OptionKey LoopExitVsLoopEndFrequencyDiff = new OptionKey<>(1000D); + //@formatter:on + } + /** * Don't allow relative frequency values to be become too small or too high as this makes * frequency calculations over- or underflow the range of a double. This commonly happens with @@ -70,6 +88,7 @@ public final class ControlFlowGraph implements AbstractControlFlowGraph { private Block[] reversePostOrder; private List> loops; private int maxDominatorDepth; + private EconomicMap localLoopFrequencyData; public interface RecursiveVisitor { V enter(Block b); @@ -77,16 +96,31 @@ public interface RecursiveVisitor { void exit(Block b, V value); } + public static ControlFlowGraph computeForSchedule(StructuredGraph graph) { + return compute(graph, true, true, true, false); + } + public static ControlFlowGraph compute(StructuredGraph graph, boolean connectBlocks, boolean computeLoops, boolean computeDominators, boolean computePostdominators) { ControlFlowGraph cfg = new ControlFlowGraph(graph); + cfg.identifyBlocks(); + + boolean loopInfoComputed = false; + if (CFGOptions.DumpEndVersusExitLoopFrequencies.getValue(graph.getOptions())) { + // additional loop info for sink frequencies inside the loop body + cfg.computeLoopInformation(); + cfg.computeDominators(); + loopInfoComputed = true; + } + cfg.computeFrequencies(); - if (computeLoops) { + if (computeLoops && !loopInfoComputed) { cfg.computeLoopInformation(); } - if (computeDominators) { + if (computeDominators && !loopInfoComputed) { cfg.computeDominators(); + assert cfg.verifyRPOInnerLoopsFirst(); } if (computePostdominators) { cfg.computePostdominators(); @@ -97,6 +131,28 @@ public static ControlFlowGraph compute(StructuredGraph graph, boolean connectBlo return cfg; } + private void identifyBlocks() { + int numBlocks = 0; + for (AbstractBeginNode begin : graph.getNodes(AbstractBeginNode.TYPE)) { + Block block = new Block(begin); + identifyBlock(block); + numBlocks++; + } + reversePostOrder = ReversePostOrder.identifyBlocks(this, numBlocks); + } + + public double localLoopFrequency(LoopBeginNode lb) { + return localLoopFrequencyData.get(lb).getLoopFrequency(); + } + + public ProfileSource localLoopFrequencySource(LoopBeginNode lb) { + return localLoopFrequencyData.get(lb).getProfileSource(); + } + + public EconomicMap getLocalLoopFrequencyData() { + return localLoopFrequencyData; + } + public String dominatorTreeString() { return dominatorTreeString(getStartBlock()); } @@ -305,6 +361,197 @@ private ControlFlowGraph(StructuredGraph graph) { this.nodeToBlock = graph.createNodeMap(); } + /** + * Utility class to verify that {@link ReversePostOrder} only produces reverse post order + * traversals of the graph that contain inner loops before outer ones. + */ + private static class RPOLoopVerification { + int endsVisited; + int exitsVisited; + LoopBeginNode lb; + + RPOLoopVerification(LoopBeginNode lb) { + this.lb = lb; + } + + boolean loopFullyProcessed() { + return lb.getLoopEndCount() == endsVisited && exitsVisited == lb.loopExits().count(); + } + + boolean allEndsVisited() { + return lb.getLoopEndCount() == endsVisited; + } + + } + + /** + * Verification method to ensure that inner loops are processed before outer ones: see + * {@link ControlFlowGraph#computeFrequencies()} for details. + */ + private boolean verifyRPOInnerLoopsFirst() { + return rpoInnerLoopsFirst(b -> { + }, b -> { + }); + } + + /** + * Special note on loop exit nodes and dominator tree loop exits: Graal has a "closed" loop + * form, this means every {@link LoopBeginNode} needs explicit {@link LoopEndNode} nodes and (if + * it is not an endless loop) {@link LoopExitNode}. For every path exiting a loop a + * {@link LoopExitNode} is required. There is one exception to that rule: + * {@link DeoptimizeNode}. + * + * Graal does not mandate that a {@link DeoptimizeNode} is preceded by a {@link LoopExitNode}. + * In the following example + * + *
+     * for (int i = 0; i < end; i++) {
+     *     if (condition) {
+     *         deoptimize;
+     *     }
+     * }
+     * 
+ * + * the IR does not have a preceding loop exit node before the deopt node. However, for regular + * control flow sinks (returns, throws, etc) like in the following example + * + *
+     * for (int i = 0; i < end; i++) {
+     *     if (condition) {
+     *         return;
+     *     }
+     * }
+     * 
+ * + * Graal IR creates a {@link LoopExitNode} before the {@link ReturnNode}. + * + * Because of the "imprecision" in the definition a regular basic block exiting a loop and a + * "dominator tree" loop exit are not necessarily the same. If a path after a control flow split + * unconditionally flows into a deopt it is a "dominator loop exit" while a regular loop exit + * block contains a {@linkplain LoopExitNode}. + */ + private boolean rpoInnerLoopsFirst(Consumer perBasicBlockOption, Consumer loopClosedAction) { + // worst case all loops in the graph are nested + RPOLoopVerification[] openLoops = new RPOLoopVerification[graph.getNodes(LoopBeginNode.TYPE).count()]; + int tos = 0; + for (Block b : reversePostOrder) { + // we see a loop end, open a new verification level in the loop stack + if (b.isLoopHeader()) { + RPOLoopVerification lv = new RPOLoopVerification((LoopBeginNode) b.getBeginNode()); + openLoops[tos++] = lv; + } + + // process this basic block + perBasicBlockOption.accept(b); + + /* + * General note on the verification of loop exits: A loop exit node and a dominator tree + * loop exit are not necessarily the same, see javadoc of this method. Ideally, we would + * like to visit all dominator loop exits during RPO verification, however we do not + * know how many there are (given the deopt issue above), thus we just determine by the + * loop exit nodes seen. + */ + boolean wasExit = predecessorBlockSequentialLoopExit(b); + + FixedNode f = b.getBeginNode(); + while (true) { + if (f instanceof LoopExitNode) { + LoopBeginNode closedLoop = ((LoopExitNode) f).loopBegin(); + RPOLoopVerification lv = openLoops[tos - 1]; + assert lv.lb == closedLoop : "Must close inner loops first before closing other ones stackLoop=" + lv.lb + " exited loop=" + closedLoop + " block=" + b; + if (!lv.allEndsVisited()) { + throw GraalError.shouldNotReachHere( + "Loop ends should be visited before exits. This is a major error in the reverse post order of the control " + + "flow graph of this method. This typically means wrongly specified control-split nodes have been processed in ReversePostOrder.java."); + } + lv.exitsVisited++; + if (lv.loopFullyProcessed()) { + loopClosedAction.accept(lv.lb); + tos--; + } + wasExit = true; + } + if (f == b.getEndNode()) { + break; + } + f = ((FixedWithNextNode) f).next(); + } + + if (b.isLoopEnd()) { + RPOLoopVerification lv = null; + LoopEndNode len = (LoopEndNode) b.getEndNode(); + int index = tos - 1; + if (wasExit) { + // irregular case a basic block that is a loop exit to an inner loop followed by + // a loop end to an outer loop, while the inner loop potentially is not + // finished, we still need to allow such cases since the code in the fraction + // between loop exit inner and end outer is fine, it does not change the + // verification logic since its a single basic block + while (openLoops[index].lb != len.loopBegin()) { + index--; + } + lv = openLoops[index]; + } else { + // regular case, this block contains a loop end to the inner most loop + lv = openLoops[tos - 1]; + } + LoopBeginNode closedLoop = ((LoopEndNode) b.getEndNode()).loopBegin(); + assert lv.lb == closedLoop : "Must close inner loops first before closing other ones stackLoop=" + lv.lb + " ended loop=" + closedLoop + " block=" + b; + lv.endsVisited++; + if (lv.loopFullyProcessed()) { + loopClosedAction.accept(lv.lb); + // the current loop was exited but we also end an outer loop, find this one and + // remove it from the verification stack since its done + if (lv.lb != openLoops[tos - 1].lb) { + // we actually finished the outer loop already completely through this + // exit-end scenario, remove it from the stack + RPOLoopVerification[] tmp = new RPOLoopVerification[openLoops.length]; + System.arraycopy(openLoops, 0, tmp, 0, index); + System.arraycopy(openLoops, index + 1, tmp, index, openLoops.length - (index + 1)); + openLoops = tmp; + } + tos--; + } + } + } + assert tos == 0 : "Unfinished loops on stack " + tos; + return true; + } + + /** + * Determine if sequential predecessor blocks of this block in a not-fully-canonicalized graph + * exit a loop. + * + * Example: Sequential basic block: loop exit -> invoke -> killing begin -> loopend/exit + * + * These cases cause problems in the {@link #verifyRPOInnerLoopsFirst()} loop verification of + * inner loop blocks because the granularity of loop ends and exits are not on block boundaries: + * a loop exit block can also be a loop end to an outer loop, which makes verification that the + * inner loop is fully processed before we process the rest of the outer loop tricky (since we + * already visit a loop end to an outer loop while we should first stricly process all loop + * ends/exits of inner loops). + */ + private static boolean predecessorBlockSequentialLoopExit(Block b) { + Block cur = b; + // while cur has a single predecessor which has a single successor which is cur, i.e., a + // sequential successor, this typically only happens in not-fully-canonicalized graphs + while (cur.getPredecessorCount() == 1 && cur.getPredecessors()[0].getSuccessorCount() == 1) { + Block pred = cur.getPredecessors()[0]; + FixedNode f = pred.getBeginNode(); + while (true) { + if (f instanceof LoopExitNode) { + return true; + } + if (f == pred.getEndNode()) { + break; + } + f = ((FixedWithNextNode) f).next(); + } + cur = cur.getPredecessors()[0]; + } + return false; + } + private void computeDominators() { assert reversePostOrder[0].getPredecessorCount() == 0 : "start block has no predecessor and therefore no dominator"; Block[] blocks = reversePostOrder; @@ -456,155 +703,318 @@ private void identifyBlock(Block block) { } } - /** - * Identify and connect blocks (including loop backward edges). Predecessors need to be in the - * order expected when iterating phi inputs. - */ - private void identifyBlocks() { - // Find all block headers. - int numBlocks = 0; - for (AbstractBeginNode begin : graph.getNodes(AbstractBeginNode.TYPE)) { - Block block = new Block(begin); - identifyBlock(block); - numBlocks++; + private void finishLocalLoopFrequency(LoopBeginNode lb) { + calculateLocalLoopFrequency(lb); + double sumAllLexFrequency = 0; + /* + * Take the sum of all exit frequencies and scale each exit with the importance in relation + * to the other exits. This factor is multiplied with the real predecessor frequency. + */ + for (LoopExitNode lex : lb.loopExits()) { + sumAllLexFrequency += blockFor(lex).relativeFrequency; } + for (LoopExitNode lex : lb.loopExits()) { + Block lexBlock = blockFor(lex); + assert lexBlock != null; + final double lexFrequency = lexBlock.getRelativeFrequency(); + final double scaleLexFrequency = lexFrequency / sumAllLexFrequency; + final double loopPredFrequency = blockFor(lb.forwardEnd()).relativeFrequency; + final double exitFrequency = multiplyRelativeFrequencies(scaleLexFrequency, loopPredFrequency); + lexBlock.setRelativeFrequency(exitFrequency); + GraalError.guarantee(blockFor(lex).relativeFrequency <= loopPredFrequency, "Lex frequency %f must be below pred frequency %f", loopPredFrequency, exitFrequency); + } + } - // Compute reverse post order. - int count = 0; - NodeMap nodeMap = this.nodeToBlock; - Block[] stack = new Block[numBlocks]; - int tos = 0; - Block startBlock = blockFor(graph.start()); - stack[0] = startBlock; - startBlock.setPredecessors(Block.EMPTY_ARRAY); - do { - Block block = stack[tos]; - int id = block.getId(); - if (id == BLOCK_ID_INITIAL) { - // First time we see this block: push all successors. - FixedNode last = block.getEndNode(); - if (last instanceof EndNode) { - EndNode endNode = (EndNode) last; - Block suxBlock = nodeMap.get(endNode.merge()); - if (suxBlock.getId() == BLOCK_ID_INITIAL) { - stack[++tos] = suxBlock; + private void computeLocalLoopFrequencies() { + rpoInnerLoopsFirst(b -> { + perBasicBlockFrequencyAction(b, true); + }, lb -> { + finishLocalLoopFrequency(lb); + }); + } + + private double calculateLocalLoopFrequency(LoopBeginNode lb) { + Block header = blockFor(lb); + assert header != null; + /* + * Ideally we would like to take the loop end frequency sum here because it respects control + * flow sinks (unwinds and deopts) inside the loop. However, semantically, if we ever exit a + * loop in compiled code it means we did not do so by an unwind or deopt but a loop exit, + * thus we ignore the end (and sink) frequencies and compute loop frequency purely based on + * the exit frequencies. + */ + double loopExitFrequencySum = 0D; + ProfileSource source = ProfileSource.UNKNOWN; + + for (LoopExitNode lex : lb.loopExits()) { + Block lexBlock = blockFor(lex); + assert lexBlock != null; + assert lexBlock.relativeFrequency >= 0D; + loopExitFrequencySum += lexBlock.relativeFrequency; + source = source.combine(lexBlock.frequencySource); + } + + loopExitFrequencySum = Math.min(1, loopExitFrequencySum); + loopExitFrequencySum = Math.max(ControlFlowGraph.MIN_RELATIVE_FREQUENCY, loopExitFrequencySum); + + double loopFrequency = -1; + loopFrequency = 1D / loopExitFrequencySum; + assert Double.isFinite(loopFrequency) : "Loop=" + lb + " Loop Frequency=" + loopFrequency + " lexFrequencySum=" + loopExitFrequencySum; + assert !Double.isNaN(loopFrequency) : "Loop=" + lb + " Loop Frequency=" + loopFrequency + " lexFrequencySum=" + loopExitFrequencySum; + + if (CFGOptions.DumpEndVersusExitLoopFrequencies.getValue(lb.getOptions())) { + debugLocalLoopFrequencies(lb, loopFrequency, loopExitFrequencySum); + } + localLoopFrequencyData.put(lb, LoopFrequencyData.create(loopFrequency, source)); + return loopFrequency; + } + + @SuppressWarnings("try") + private void debugLocalLoopFrequencies(LoopBeginNode lb, final double loopFrequency, final double loopExitFrequencySum) { + try (DebugContext.Scope s = lb.getDebug().scope("CFGFrequencyInfo")) { + /* + * For loops without loop exit nodes we may only have deopt loop exit paths, they are + * however not part of the loop data structure of a Loop, thus it might be that the + * reverse post order did not yet visit all sinks + */ + boolean sinkingImplicitExitsFullyVisited = true; + double loopSinkFrequencySum = 0D; + for (Block loopBlock : blockFor(lb).getLoop().getBlocks()) { + FixedNode blockEndNode = loopBlock.getEndNode(); + if (blockEndNode instanceof ControlSinkNode) { + double sinkBlockFrequency = blockFor(blockEndNode).relativeFrequency; + loopSinkFrequencySum += sinkBlockFrequency; + } + if (blockFor(blockEndNode).relativeFrequency == -1D) { + sinkingImplicitExitsFullyVisited = false; + } + } + final double delta = 0.001D; + if (sinkingImplicitExitsFullyVisited) { + // verify integrity of the CFG so far + outer: for (Block loopBlock : blockFor(lb).getLoop().getBlocks()) { + if (loopBlock.isLoopHeader()) { + // loop exit successor frequency is weighted differently + continue; } - block.setSuccessors(new Block[]{suxBlock}); - } else if (last instanceof IfNode) { - IfNode ifNode = (IfNode) last; - Block trueSucc = nodeMap.get(ifNode.trueSuccessor()); - stack[++tos] = trueSucc; - Block falseSucc = nodeMap.get(ifNode.falseSuccessor()); - stack[++tos] = falseSucc; - block.setSuccessors(new Block[]{trueSucc, falseSucc}); - Block[] ifPred = new Block[]{block}; - trueSucc.setPredecessors(ifPred); - falseSucc.setPredecessors(ifPred); - } else if (last instanceof LoopEndNode) { - LoopEndNode loopEndNode = (LoopEndNode) last; - block.setSuccessors(new Block[]{nodeMap.get(loopEndNode.loopBegin())}); - // Nothing to do push onto the stack. - } else if (last instanceof ControlSinkNode) { - block.setSuccessors(Block.EMPTY_ARRAY); - } else { - assert !(last instanceof AbstractEndNode) : "Algorithm only supports EndNode and LoopEndNode."; - int startTos = tos; - Block[] ifPred = new Block[]{block}; - for (Node suxNode : last.successors()) { - Block sux = nodeMap.get(suxNode); - stack[++tos] = sux; - sux.setPredecessors(ifPred); + for (Block succ : loopBlock.getSuccessors()) { + if (isDominatorTreeLoopExit(succ)) { + // loop exit successor frequency is weighted differently + continue outer; + } + if (succ.isLoopHeader()) { + // header frequency is set to 1 artificially to compute local + // frequencies + continue outer; + } + } + final double selfFrequency = loopBlock.relativeFrequency; + double succFrequency = 0D; + for (Block succ : loopBlock.getSuccessors()) { + succFrequency += succ.relativeFrequency; + } + if (loopBlock.getSuccessorCount() == 0) { + GraalError.guarantee(loopBlock.getEndNode() instanceof ControlSinkNode, "Must sink if there is no successor"); + // frequency "lost" + continue; + } + if (succFrequency < selfFrequency - delta) { + String format = "Successors must add up for block %s with begin %s, selfF=%f succF=%f"; + graph.getDebug().dump(DebugContext.VERBOSE_LEVEL, graph, format, loopBlock, loopBlock.getBeginNode(), selfFrequency, succFrequency); + throw GraalError.shouldNotReachHere(String.format(format, loopBlock, loopBlock.getBeginNode(), selfFrequency, succFrequency)); } - int suxCount = tos - startTos; - Block[] successors = new Block[suxCount]; - System.arraycopy(stack, startTos + 1, successors, 0, suxCount); - block.setSuccessors(successors); } - block.setId(BLOCK_ID_VISITED); - AbstractBeginNode beginNode = block.getBeginNode(); - if (beginNode instanceof LoopBeginNode) { - computeLoopPredecessors(nodeMap, block, (LoopBeginNode) beginNode); - } else if (beginNode instanceof AbstractMergeNode) { - AbstractMergeNode mergeNode = (AbstractMergeNode) beginNode; - int forwardEndCount = mergeNode.forwardEndCount(); - Block[] predecessors = new Block[forwardEndCount]; - for (int i = 0; i < forwardEndCount; ++i) { - predecessors[i] = nodeMap.get(mergeNode.forwardEndAt(i)); + } + double loopEndFrequencySum = 0D; + for (LoopEndNode len : lb.loopEnds()) { + Block lenBlock = blockFor(len); + loopEndFrequencySum += lenBlock.relativeFrequency; + } + double endBasedFrequency = 1 / (1 - loopEndFrequencySum); + if (loopEndFrequencySum == 1D) { + // loop without any loop exits (and no sinks) + endBasedFrequency = MAX_RELATIVE_FREQUENCY; + } + // verify inner loop frequency calculations used sane loop exit frequencies + for (Block loopBlock : blockFor(lb).getLoop().getBlocks()) { + if (loopBlock.isLoopHeader() && loopBlock.getBeginNode() != lb) { + LoopBeginNode otherLoop = (LoopBeginNode) loopBlock.getBeginNode(); + double otherLoopExitFrequencySum = 0D; + for (LoopExitNode lex : otherLoop.loopExits()) { + otherLoopExitFrequencySum += blockFor(lex).relativeFrequency; } - block.setPredecessors(predecessors); + // forward end + final double predFrequency = loopBlock.getFirstPredecessor().relativeFrequency; + GraalError.guarantee(Math.abs(predFrequency - otherLoopExitFrequencySum) <= delta, "Frequencies diverge too much"); } - - } else if (id == BLOCK_ID_VISITED) { - // Second time we see this block: All successors have been processed, so add block - // to result list. Can safely reuse the stack for this. - --tos; - count++; - int index = numBlocks - count; - stack[index] = block; - block.setId(index); - } else { - throw GraalError.shouldNotReachHere(); } - } while (tos >= 0); + /* + * "Endless" looking loops, i.e., loops without exit nodes (only deopt exits) look like + * inifinite loops if we take an exit frequency of "0", which results in max frequency + */ + final boolean hasLoopExits = lb.loopExits().count() > 0; + if (Math.abs(endBasedFrequency - loopFrequency) > CFGOptions.LoopExitVsLoopEndFrequencyDiff.getValue(lb.getOptions()) && hasLoopExits) { + graph.getDebug().dump(DebugContext.VERBOSE_LEVEL, graph, + "Frequency divergence for loop %s,exitBasedFrequency=%.4f endBasedFrequency=%.4f, exitFSum=%.2f / endFSum=%.2f/ sinkSum=%.2f [allSum=%f]", lb, + loopFrequency, endBasedFrequency, loopExitFrequencySum, loopEndFrequencySum, + loopSinkFrequencySum, + (loopExitFrequencySum + loopEndFrequencySum + loopSinkFrequencySum)); + } + } + } - // Compute reverse postorder and number blocks. - assert count == numBlocks : "all blocks must be reachable"; - this.reversePostOrder = stack; + private void resetBlockFrequencies() { + for (Block block : reversePostOrder) { + block.setRelativeFrequency(0); + } } - private static void computeLoopPredecessors(NodeMap nodeMap, Block block, LoopBeginNode loopBeginNode) { - int forwardEndCount = loopBeginNode.forwardEndCount(); - LoopEndNode[] loopEnds = loopBeginNode.orderedLoopEnds(); - Block[] predecessors = new Block[forwardEndCount + loopEnds.length]; - for (int i = 0; i < forwardEndCount; ++i) { - predecessors[i] = nodeMap.get(loopBeginNode.forwardEndAt(i)); + private void computeFrequenciesFromLocal() { + for (Block block : reversePostOrder) { + perBasicBlockFrequencyAction(block, false); } - for (int i = 0; i < loopEnds.length; ++i) { - predecessors[i + forwardEndCount] = nodeMap.get(loopEnds[i]); + } + + private void perBasicBlockFrequencyAction(Block b, boolean computingLocalLoopFrequencies) { + double relativeFrequency = -1D; + ProfileSource source = ProfileSource.UNKNOWN; + Block[] predecessors = b.getPredecessors(); + if (predecessors.length == 0) { + relativeFrequency = 1D; + } else if (predecessors.length == 1) { + Block pred = predecessors[0]; + relativeFrequency = pred.relativeFrequency; + if (pred.getSuccessorCount() > 1) { + assert pred.getEndNode() instanceof ControlSplitNode; + ControlSplitNode controlSplit = (ControlSplitNode) pred.getEndNode(); + relativeFrequency = multiplyRelativeFrequencies(relativeFrequency, controlSplit.probability(b.getBeginNode())); + if (computingLocalLoopFrequencies) { + source = controlSplit.getProfileData().getProfileSource(); + } + } + } else { + relativeFrequency = predecessors[0].relativeFrequency; + for (int i = 1; i < predecessors.length; ++i) { + relativeFrequency += predecessors[i].relativeFrequency; + if (computingLocalLoopFrequencies) { + if (predecessors[i].frequencySource != null) { + source = source.combine(predecessors[i].frequencySource); + } + } + } + if (b.getBeginNode() instanceof LoopBeginNode) { + if (computingLocalLoopFrequencies) { + // start with a "local" loop, i.e., assume no dominating code with different + // frequencies + relativeFrequency = 1D; + source = ProfileSource.UNKNOWN; + } else { + // take the previously computed local frequency + LoopBeginNode loopBegin = (LoopBeginNode) b.getBeginNode(); + relativeFrequency = multiplyRelativeFrequencies(relativeFrequency, localLoopFrequencyData.get(loopBegin).getLoopFrequency()); + } + } + } + if (relativeFrequency < MIN_RELATIVE_FREQUENCY) { + relativeFrequency = MIN_RELATIVE_FREQUENCY; + } else if (relativeFrequency > MAX_RELATIVE_FREQUENCY) { + relativeFrequency = MAX_RELATIVE_FREQUENCY; + } + + b.setRelativeFrequency(relativeFrequency); + if (computingLocalLoopFrequencies) { + b.setFrequencySource(source); } - block.setPredecessors(predecessors); } - /** - * Computes the frequencies of all blocks relative to the start block. It uses the probability - * information attached to control flow splits to calculate the frequency of a block based on - * the frequency of its predecessor and the probability of its incoming control flow branch. + //@formatter:off + /* + * Compute the frequency data for the entire control flow graph. + * In the following documentation the term "local loop frequency" describes the frequency of a loop + * without any enclosing code, i.e., the loop in a form where it is not dominated by any other control flow. + * + * The real frequency of a loop is then the result of multiplying the local loop frequency with the frequency + * of the basic block dominating the loop. + * + * Consider the following CFG: + * + * + * + * [B0: Loop 1 Header] + * | + * [B1:if] + * / \ + * [B2: Loop 2 Header] [B9: Loop Exit Loop1 + Return] + * | + * [B3: If] + * / \ + * [B4: LoopEnd Loop2] [B5: LoopExit Loop2 + If] + * / \ + * [B6] [B7] + * \ / + * [B8:Merge + LoopEnd Loop1] + * + * + * The frequency of the loop exit basic blocks depends on the frequency of the loop header. + * Why? Because the loop header is visited multiple times so the frequency of the loop exit block + * has to be multiplied by the frequency of the loop header (which is the frequency of all loop + * end blocks combined). The frequency of the loop header can be derived by summing up the frequency + * of all loop end blocks which gives us the frequency for exiting the loop (1- sumLoopEndFrequency). + * The frequency of the loop can then be calculated by 1 / frequencyToExitTheLoop. + * + * In a final step we multiply the frequency of each exit with the frequency to exit the overall + * loop to account for the loop frequency. + * + * Ideally we would only process all basic blocks once here, however, given that the frequency of an + * outer loop depends on loop end frequencies which can depend on the frequency of inner loops, + * we either ensure to process inner loops first or perform the entire process until a fix point is reached. + * + * However, we can utilize a "smart" reverse post order with inner loops first to reach that goal. + * + * Graph theory states that there are multiple correct reverse post order (RPO) traversals + * for any given graph. Consider for example the following RPO for the CFG above: + * [B0,B1,B2,B3,B4,B5,B6,B7,B8,B9] + * + * The inner loop is sequentially in the traversal, thus we can compute its local frequency and + * then propagate it outwards by processing the entire CFG once again. + * + * However, there are other valid RPOs that do not allow a single pass over all loops to calculate local + * frequencies: e.g. [B0,B1,B9,B2,B3,B5,B6,B7,B8,B4], thus this phase ensures that we have the "right" RPO. + * + * Implementation notes: + * The algorithm to compute the loop frequencies works in two passes: the first pass computes + * the local loop frequencies, i.e., for every loop predecessor block a relative frequency of 1 + * is assumed, then the frequency inside the loop is propagated and multiplied by control split + * probabilities. If a loop is finished the exit frequency is set accordingly. + * + * The second pass then propagates relative frequencies into the entire CFG by using the, + * already correct, local loop frequencies for the body of the loop. */ + //@formatter:on private void computeFrequencies() { + /* + * General note: While it is not verified that the reverse post order contains inner loops + * first yet, this will be verified once we calculate dominance information, thus we should + * be good here. + */ + localLoopFrequencyData = EconomicMap.create(); - for (Block block : reversePostOrder) { - Block[] predecessors = block.getPredecessors(); - - double relativeFrequency; - if (predecessors.length == 0) { - relativeFrequency = 1D; - } else if (predecessors.length == 1) { - Block pred = predecessors[0]; - relativeFrequency = pred.relativeFrequency; - if (pred.getSuccessorCount() > 1) { - assert pred.getEndNode() instanceof ControlSplitNode; - ControlSplitNode controlSplit = (ControlSplitNode) pred.getEndNode(); - relativeFrequency = multiplyRelativeFrequencies(relativeFrequency, controlSplit.probability(block.getBeginNode())); - } - } else { - relativeFrequency = predecessors[0].relativeFrequency; - for (int i = 1; i < predecessors.length; ++i) { - relativeFrequency += predecessors[i].relativeFrequency; - } + // pass 1 compute "local" loop frequencies, i.e., the actual frequency of each self + // contained loop, inner loops first, then outer loops + computeLocalLoopFrequencies(); - if (block.getBeginNode() instanceof LoopBeginNode) { - LoopBeginNode loopBegin = (LoopBeginNode) block.getBeginNode(); - relativeFrequency = multiplyRelativeFrequencies(relativeFrequency, loopBegin.loopFrequency()); - } - } - if (relativeFrequency < MIN_RELATIVE_FREQUENCY) { - relativeFrequency = MIN_RELATIVE_FREQUENCY; - } else if (relativeFrequency > MAX_RELATIVE_FREQUENCY) { - relativeFrequency = MAX_RELATIVE_FREQUENCY; + // reset everything again + resetBlockFrequencies(); + + // pass 2 propagate the outer frequencies into the inner ones multiplying the local loop + // frequencies by the loop predecessor frequencies + computeFrequenciesFromLocal(); + + if (Assertions.assertionsEnabled()) { + for (Block block : reversePostOrder) { + assert block.getRelativeFrequency() >= 0 : "Must have a relative frequency set, block " + block; } - block.setRelativeFrequency(relativeFrequency); } - } private void computeLoopInformation() { @@ -754,6 +1164,10 @@ public void setNodeToBlock(NodeMap nodeMap) { this.nodeToBlock = nodeMap; } + public static double multiplyRelativeFrequencies(double a, double b, double c) { + return multiplyRelativeFrequencies(multiplyRelativeFrequencies(a, b), c); + } + /** * Multiplies a and b and clamps the between {@link ControlFlowGraph#MIN_RELATIVE_FREQUENCY} and * {@link ControlFlowGraph#MAX_RELATIVE_FREQUENCY}. diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ReversePostOrder.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ReversePostOrder.java new file mode 100644 index 000000000000..3711039030ef --- /dev/null +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ReversePostOrder.java @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.nodes.cfg; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Deque; +import java.util.Iterator; + +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.MapCursor; +import org.graalvm.compiler.debug.Assertions; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeMap; +import org.graalvm.compiler.nodes.AbstractBeginNode; +import org.graalvm.compiler.nodes.AbstractEndNode; +import org.graalvm.compiler.nodes.AbstractMergeNode; +import org.graalvm.compiler.nodes.ControlSinkNode; +import org.graalvm.compiler.nodes.ControlSplitNode; +import org.graalvm.compiler.nodes.EndNode; +import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.LoopBeginNode; +import org.graalvm.compiler.nodes.LoopEndNode; +import org.graalvm.compiler.nodes.LoopExitNode; +import org.graalvm.compiler.nodes.MergeNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.spi.Canonicalizable; +import org.graalvm.compiler.nodes.spi.Simplifiable; + +/** + * Utility class computing a reverse post order of the {@link ControlFlowGraph}. + * + * The block order is special in that {@linkplain LoopEndNode blocks} are processed before + * {@linkplain LoopExitNode blocks}. This has the advantage that for + * {@linkplain Block#getRelativeFrequency() basic block frequency calculations} nested loops are + * processed before the outer loop exit blocks allowing a linear computation of loop frequencies. + */ +public class ReversePostOrder { + + /** + * Utility class for eager basic block creation. The CFG will create the shortest possible basic + * blocks within the given control flow graph: this class has to ensure that predecessor and + * successor blocks are set accordingly. + * + * "Shortest" possible is a special case in that, if a {@link StructuredGraph} is not fully + * {@linkplain Canonicalizable canonicalized}, i.e., it contains redundant + * {@link AbstractBeginNode}, each {@link AbstractBeginNode} will form a new basic block. + * + * This is necessary given that we do not want to run a full canonicalization and CFG + * {@linkplain Simplifiable simplification}} every time to compute the {@link ControlFlowGraph}. + */ + private static class TraversalQueueHandler { + private final ControlFlowGraph cfg; + /** + * The result reverse post order block list. + */ + private final Block[] reversePostOrder; + /** + * Index of the next block to be added to {@link #reversePostOrder}. + */ + private int nextBlockIndex; + private final NodeMap nodeMap; + + TraversalQueueHandler(ControlFlowGraph cfg, int numBlocks) { + this.cfg = cfg; + this.nodeMap = cfg.getNodeToBlock(); + reversePostOrder = new Block[numBlocks]; + nextBlockIndex = 0; + } + + /** + * Graal IR has certain requirements with respect to what can be a + * {@link Block#getBeginNode()} and {@link Block#getEndNode()}: Every + * {@link AbstractBeginNode} forms a new {@link Block}. This method must ensure + * {@link Block#getPredecessors()} and {@link Block#getSuccessors()} are set accordingly. + */ + protected Block potentiallySplitBlock(FixedNode currentNode, Block currentBlock) { + assert currentBlock != null : "Block must not be null for node " + currentNode; + if (currentBlock.getBeginNode() == currentNode) { + /* + * We process a block begin node add the block to the next index in the traversal + * and set the predecessors accordingly. + */ + Block b = cfg.blockFor(currentNode); + reversePostOrder[nextBlockIndex] = b; + b.setId(nextBlockIndex); + nextBlockIndex++; + + if (currentNode instanceof LoopBeginNode) { + computeLoopPredecessors(nodeMap, currentBlock, (LoopBeginNode) currentNode); + } else if (currentNode instanceof AbstractMergeNode) { + AbstractMergeNode mergeNode = (AbstractMergeNode) currentNode; + int forwardEndCount = mergeNode.forwardEndCount(); + Block[] predecessors = new Block[forwardEndCount]; + for (int i = 0; i < forwardEndCount; ++i) { + predecessors[i] = nodeMap.get(mergeNode.forwardEndAt(i)); + } + currentBlock.setPredecessors(predecessors); + } + } + if (currentBlock.getEndNode() == currentNode) { + /** + * We process a block end node: create the necessary successor and set them + * accordingly. + */ + if (currentNode instanceof EndNode) { + // next node is a merge, update successors + EndNode endNode = (EndNode) currentNode; + Block suxBlock = nodeMap.get(endNode.merge()); + currentBlock.setSuccessors(new Block[]{suxBlock}); + } else if (currentNode instanceof ControlSplitNode) { + // next is a split, set successors and predecessors accordingly for the split + ArrayList succ = new ArrayList<>(); + Block[] ifPred = new Block[]{currentBlock}; + for (Node sux : currentNode.successors()) { + Block sucBlock = nodeMap.get(sux); + succ.add(sucBlock); + sucBlock.setPredecessors(ifPred); + } + currentBlock.setSuccessors(succ.toArray(new Block[succ.size()])); + } else if (currentNode instanceof LoopEndNode) { + LoopEndNode loopEndNode = (LoopEndNode) currentNode; + currentBlock.setSuccessors(new Block[]{nodeMap.get(loopEndNode.loopBegin())}); + } else if (currentNode instanceof ControlSinkNode) { + currentBlock.setSuccessors(Block.EMPTY_ARRAY); + } else { + assert !(currentNode instanceof AbstractEndNode) : "Algorithm only supports EndNode and LoopEndNode."; + Block[] ifPred = new Block[]{currentBlock}; + for (Node suxNode : currentNode.successors()) { + Block sux = nodeMap.get(suxNode); + sux.setPredecessors(ifPred); + } + assert currentNode.successors().count() == 1 : "Node " + currentNode; + Block sequentialSuc = nodeMap.get(currentNode.successors().first()); + currentBlock.setSuccessors(new Block[]{sequentialSuc}); + return sequentialSuc; + } + } + return currentBlock; + } + + private LoopInfo processLoop(LoopBeginNode loop) { + EconomicMap blockEndStates = apply(this, loop, cfg.blockFor(loop), loop); + LoopInfo info = new LoopInfo(loop.loopEnds().count(), loop.loopExits().count()); + for (LoopEndNode end : loop.loopEnds()) { + if (blockEndStates.containsKey(end)) { + info.endStates.put(end, blockEndStates.get(end)); + blockEndStates.removeKey(end); + } + } + for (LoopExitNode exit : loop.loopExits()) { + if (blockEndStates.containsKey(exit)) { + info.exitStates.put(exit, blockEndStates.get(exit)); + blockEndStates.removeKey(exit); + } + } + /* + * Deopt grouping can create loop exits without loop exit nodes that do not sink but + * merge + */ + for (FixedNode f : blockEndStates.getKeys()) { + info.naturalExits.put(f, blockEndStates.get(f)); + } + return info; + } + + private Block enqueBlockUnconditionally(FixedNode newBlockBegin) { + return cfg.blockFor(newBlockBegin); + } + + } + + private static class LoopInfo { + public final EconomicMap endStates; + public final EconomicMap exitStates; + public final EconomicMap naturalExits; + + LoopInfo(int endCount, int exitCount) { + endStates = EconomicMap.create(Equivalence.IDENTITY, endCount); + exitStates = EconomicMap.create(Equivalence.IDENTITY, exitCount); + naturalExits = EconomicMap.create(Equivalence.IDENTITY, exitCount); + } + } + + private static EconomicMap apply(TraversalQueueHandler traversalHandler, FixedNode start, Block initialBlock, LoopBeginNode boundary) { + assert start != null; + Deque nodeQueue = new ArrayDeque<>(); + EconomicMap blockEndStates = EconomicMap.create(Equivalence.IDENTITY); + + Block currentBlock = initialBlock; + + FixedNode currentFixedNode = start; + + do { + while (currentFixedNode instanceof FixedWithNextNode) { + if (boundary != null && currentFixedNode instanceof LoopExitNode && ((LoopExitNode) currentFixedNode).loopBegin() == boundary) { + blockEndStates.put(currentFixedNode, currentBlock); + currentFixedNode = null; + } else { + FixedNode next = ((FixedWithNextNode) currentFixedNode).next(); + currentBlock = traversalHandler.potentiallySplitBlock(currentFixedNode, currentBlock); + currentFixedNode = next; + } + } + + if (currentFixedNode != null) { + currentBlock = traversalHandler.potentiallySplitBlock(currentFixedNode, currentBlock); + + Iterator successors = currentFixedNode.successors().iterator(); + if (!successors.hasNext()) { + if (currentFixedNode instanceof LoopEndNode) { + blockEndStates.put(currentFixedNode, currentBlock); + } else if (currentFixedNode instanceof EndNode) { + // add the end node and see if the merge is ready for processing + AbstractMergeNode merge = ((EndNode) currentFixedNode).merge(); + if (merge instanceof LoopBeginNode) { + Block toProcess = processLoop(merge, currentFixedNode, currentBlock, blockEndStates, nodeQueue, traversalHandler); + if (toProcess != null) { + currentBlock = toProcess; + } + } else { + if (endsVisited(merge, currentFixedNode, blockEndStates)) { + currentBlock = merge(merge, currentFixedNode, currentBlock, blockEndStates, nodeQueue, traversalHandler); + } else { + assert !blockEndStates.containsKey(currentFixedNode); + blockEndStates.put(currentFixedNode, currentBlock); + } + } + } + } else { + FixedNode firstSuccessor = (FixedNode) successors.next(); + if (!successors.hasNext()) { + if (currentFixedNode instanceof ControlSplitNode) { + // strange split with a single successor, do not record the block end + // state since we will immediately process the next block + currentBlock = traversalHandler.enqueBlockUnconditionally(firstSuccessor); + } + currentFixedNode = firstSuccessor; + continue; + } else { + // first direct successor + currentBlock = traversalHandler.enqueBlockUnconditionally(firstSuccessor); + nodeQueue.addLast((AbstractBeginNode) firstSuccessor); + blockEndStates.put(firstSuccessor, currentBlock); + do { + AbstractBeginNode successor = (AbstractBeginNode) successors.next(); + Block successorState = traversalHandler.enqueBlockUnconditionally(successor); + blockEndStates.put(successor, successorState); + nodeQueue.addLast(successor); + + } while (successors.hasNext()); + } + + } + } + if (nodeQueue.isEmpty()) { + return blockEndStates; + } else { + currentFixedNode = nodeQueue.removeFirst(); + assert blockEndStates.containsKey(currentFixedNode); + currentBlock = blockEndStates.removeKey(currentFixedNode); + } + } while (true); + } + + private static Block processLoop(AbstractMergeNode merge, FixedNode currentFixedNode, Block currentBlock, EconomicMap blockEndStates, Deque nodeQueue, + TraversalQueueHandler blockSplitter) { + + Block nextCurrentBlock = null; + LoopInfo loopInfo = blockSplitter.processLoop((LoopBeginNode) merge); + EconomicMap loopExitState = loopInfo.exitStates; + MapCursor entry = loopExitState.getEntries(); + + // process loop exit blocks in their increasing node id next + ArrayList lexs = new ArrayList<>(); + while (entry.advance()) { + blockEndStates.put(entry.getKey(), entry.getValue()); + lexs.add(entry.getKey()); + } + for (int i = lexs.size() - 1; i >= 0; i--) { + // process loop exits next + nodeQueue.addFirst(lexs.get(i)); + } + MapCursor naturalExits = loopInfo.naturalExits.getEntries(); + while (naturalExits.advance()) { + FixedNode naturalExit = naturalExits.getKey(); + if (naturalExit instanceof EndNode) { + blockEndStates.put(naturalExit, naturalExits.getValue()); + MergeNode mergeAfter = (MergeNode) ((EndNode) naturalExit).merge(); + if (endsVisited(mergeAfter, currentFixedNode, blockEndStates)) { + nextCurrentBlock = merge(mergeAfter, currentFixedNode, currentBlock, blockEndStates, nodeQueue, blockSplitter); + } + } else { + GraalError.shouldNotReachHere("Can only exit a loop " + merge + " naturally with a merge without a loop exit " + naturalExit); + } + } + + return nextCurrentBlock; + } + + private static boolean endsVisited(AbstractMergeNode merge, FixedNode currentFixedNode, EconomicMap blockEndStates) { + for (AbstractEndNode forwardEnd : merge.forwardEnds()) { + if (forwardEnd != currentFixedNode && !blockEndStates.containsKey(forwardEnd)) { + return false; + } + } + return true; + } + + private static Block merge(AbstractMergeNode merge, FixedNode currentFixedNode, Block currentBlock, EconomicMap blockEndStates, Deque nodeQueue, + TraversalQueueHandler blockSplitter) { + ArrayList states = new ArrayList<>(merge.forwardEndCount()); + for (int i = 0; i < merge.forwardEndCount(); i++) { + AbstractEndNode forwardEnd = merge.forwardEndAt(i); + assert forwardEnd == currentFixedNode || blockEndStates.containsKey(forwardEnd); + Block other = forwardEnd == currentFixedNode ? currentBlock : blockEndStates.removeKey(forwardEnd); + states.add(other); + } + Block nextCurrentBlock = blockSplitter.enqueBlockUnconditionally(merge); + nodeQueue.addLast(merge); + blockEndStates.put(merge, nextCurrentBlock); + return nextCurrentBlock; + } + + private static void computeLoopPredecessors(NodeMap nodeMap, Block block, LoopBeginNode loopBeginNode) { + int forwardEndCount = loopBeginNode.forwardEndCount(); + LoopEndNode[] loopEnds = loopBeginNode.orderedLoopEnds(); + Block[] predecessors = new Block[forwardEndCount + loopEnds.length]; + for (int i = 0; i < forwardEndCount; ++i) { + predecessors[i] = nodeMap.get(loopBeginNode.forwardEndAt(i)); + } + for (int i = 0; i < loopEnds.length; ++i) { + predecessors[i + forwardEndCount] = nodeMap.get(loopEnds[i]); + } + block.setPredecessors(predecessors); + } + + public static Block[] identifyBlocks(ControlFlowGraph cfg, int numBlocks) { + NodeMap nodeMap = cfg.getNodeToBlock(); + TraversalQueueHandler c = new TraversalQueueHandler(cfg, numBlocks); + Block startBlock = cfg.blockFor(cfg.graph.start()); + startBlock.setPredecessors(Block.EMPTY_ARRAY); + apply(c, cfg.graph.start(), startBlock, null); + if (Assertions.detailedAssertionsEnabled(cfg.graph.getOptions())) { + outer: for (Block b : nodeMap.getValues()) { + for (int i = 0; i < c.reversePostOrder.length; i++) { + if (c.reversePostOrder[i] == b) { + continue outer; + } + } + GraalError.shouldNotReachHere("No mapping in reverse post oder for block " + b); + } + for (int i = 0; i < c.reversePostOrder.length; i++) { + assert c.reversePostOrder[i] != null : "Null entry for block " + i + " Blocks " + Arrays.toString(c.reversePostOrder); + assert c.reversePostOrder[i].getPredecessors() != null : "Pred null for block " + c.reversePostOrder[i]; + assert c.reversePostOrder[i].getSuccessors() != null : "Succ null for block " + c.reversePostOrder[i]; + } + } + return c.reversePostOrder; + } + +} diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ArrayRangeWrite.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ArrayRangeWrite.java index 317277c80ac2..8f99a52dd0a3 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ArrayRangeWrite.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ArrayRangeWrite.java @@ -24,14 +24,13 @@ */ package org.graalvm.compiler.nodes.extended; -import org.graalvm.compiler.graph.NodeInterface; import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.FixedWithNextNodeInterface; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.memory.FixedAccessNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; -public interface ArrayRangeWrite extends NodeInterface { +public interface ArrayRangeWrite extends FixedWithNextNodeInterface { AddressNode getAddress(); /** @@ -53,9 +52,6 @@ public interface ArrayRangeWrite extends NodeInterface { int getElementStride(); - @Override - FixedAccessNode asNode(); - /** * Returns the place where a pre-write barrier should be inserted if one is necessary for this * node. The barrier should be added before the node returned by this method. diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BoxNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BoxNode.java index 3e3798cd662c..24116dee464c 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BoxNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BoxNode.java @@ -36,8 +36,6 @@ import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.Node.IndirectCanonicalization; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.Canonicalizable; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodeinfo.InputType; import org.graalvm.compiler.nodeinfo.NodeCycles; import org.graalvm.compiler.nodeinfo.NodeInfo; @@ -48,6 +46,8 @@ import org.graalvm.compiler.nodes.calc.FloatingNode; import org.graalvm.compiler.nodes.java.MonitorIdNode; import org.graalvm.compiler.nodes.memory.SingleMemoryKill; +import org.graalvm.compiler.nodes.spi.Canonicalizable; +import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.nodes.spi.Virtualizable; @@ -65,7 +65,7 @@ * This node represents the boxing of a primitive value. This corresponds to a call to the valueOf * methods in Integer, Long, etc. */ -@NodeInfo(cycles = NodeCycles.CYCLES_8, size = SIZE_16, allowedUsageTypes = {InputType.Memory, InputType.Value}) +@NodeInfo(cycles = NodeCycles.CYCLES_8, size = SIZE_16, allowedUsageTypes = {InputType.Value}) public abstract class BoxNode extends AbstractBoxingNode implements IterableNodeType, VirtualizableAllocation, Lowerable, Canonicalizable.Unary, IndirectCanonicalization { public static final NodeClass TYPE = NodeClass.create(BoxNode.class); @@ -154,7 +154,7 @@ public void virtualize(VirtualizerTool tool) { tool.replaceWithVirtual(newVirtual); } - @NodeInfo(cycles = NodeCycles.CYCLES_8, size = SIZE_8, allowedUsageTypes = {InputType.Memory, InputType.Value}) + @NodeInfo(cycles = NodeCycles.CYCLES_8, size = SIZE_8, allowedUsageTypes = {InputType.Value}) private static class PureBoxNode extends BoxNode { public static final NodeClass TYPE = NodeClass.create(PureBoxNode.class); @@ -211,7 +211,7 @@ public ValueNode getValue() { @Override public void lower(LoweringTool tool) { if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.MID_TIER) { - replaceAtAllUsages(value, this); + replaceAtAllUsages(value, true); } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java index a048182f8cde..e5b93a5e1da9 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java @@ -122,6 +122,12 @@ public enum BytecodeExceptionKind { */ ILLEGAL_ARGUMENT_EXCEPTION_ARGUMENT_IS_NOT_AN_ARRAY(0, IllegalArgumentException.class, "Argument is not an array"), + /** + * Represents a {@link NegativeArraySizeException} with one required int argument for the + * length of the array. + */ + NEGATIVE_ARRAY_SIZE(1, NegativeArraySizeException.class), + /** * Represents a {@link ArithmeticException}, with the exception message indicating a * division by zero. No arguments are allowed. @@ -157,6 +163,10 @@ public enum BytecodeExceptionKind { public String getExceptionMessage() { return exceptionMessage; } + + public int getNumArguments() { + return numArguments; + } } public static final NodeClass TYPE = NodeClass.create(BytecodeExceptionNode.class); diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadHubNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadHubNode.java index 810d0e748d20..d45628666477 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadHubNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadHubNode.java @@ -24,7 +24,6 @@ */ package org.graalvm.compiler.nodes.extended; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; @@ -91,36 +90,30 @@ public LoadHubNode(Stamp stamp, ValueNode value) { @Override public ValueNode canonical(CanonicalizerTool tool) { - if (!GeneratePIC.getValue(tool.getOptions())) { - NodeView view = NodeView.from(tool); - MetaAccessProvider metaAccess = tool.getMetaAccess(); - ValueNode curValue = getValue(); - ValueNode newNode = findSynonym(curValue, stamp(view), metaAccess, tool.getConstantReflection()); - if (newNode != null) { - return newNode; - } + NodeView view = NodeView.from(tool); + MetaAccessProvider metaAccess = tool.getMetaAccess(); + ValueNode curValue = getValue(); + ValueNode newNode = findSynonym(curValue, stamp(view), metaAccess, tool.getConstantReflection()); + if (newNode != null) { + return newNode; } return this; } public static ValueNode findSynonym(ValueNode curValue, Stamp stamp, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) { - if (!GeneratePIC.getValue(curValue.getOptions())) { - TypeReference type = StampTool.typeReferenceOrNull(curValue); - if (type != null && type.isExact()) { - return ConstantNode.forConstant(stamp, constantReflection.asObjectHub(type.getType()), metaAccess); - } + TypeReference type = StampTool.typeReferenceOrNull(curValue); + if (type != null && type.isExact()) { + return ConstantNode.forConstant(stamp, constantReflection.asObjectHub(type.getType()), metaAccess); } return null; } @Override public void virtualize(VirtualizerTool tool) { - if (!GeneratePIC.getValue(tool.getOptions())) { - ValueNode alias = tool.getAlias(getValue()); - TypeReference type = StampTool.typeReferenceOrNull(alias); - if (type != null && type.isExact()) { - tool.replaceWithValue(ConstantNode.forConstant(stamp(NodeView.DEFAULT), tool.getConstantReflection().asObjectHub(type.getType()), tool.getMetaAccess(), graph())); - } + ValueNode alias = tool.getAlias(getValue()); + TypeReference type = StampTool.typeReferenceOrNull(alias); + if (type != null && type.isExact()) { + tool.replaceWithValue(ConstantNode.forConstant(stamp(NodeView.DEFAULT), tool.getConstantReflection().asObjectHub(type.getType()), tool.getMetaAccess(), graph())); } } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadHubOrNullNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadHubOrNullNode.java index 40d71ad59aa2..7f509542d73c 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadHubOrNullNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadHubOrNullNode.java @@ -24,7 +24,6 @@ */ package org.graalvm.compiler.nodes.extended; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; @@ -91,14 +90,12 @@ public LoadHubOrNullNode(Stamp stamp, ValueNode value) { @Override public ValueNode canonical(CanonicalizerTool tool) { - if (!GeneratePIC.getValue(tool.getOptions())) { - NodeView view = NodeView.from(tool); - MetaAccessProvider metaAccess = tool.getMetaAccess(); - ValueNode curValue = getValue(); - ValueNode newNode = findSynonym(curValue, (AbstractPointerStamp) stamp(view), metaAccess, tool.getConstantReflection()); - if (newNode != null) { - return newNode; - } + NodeView view = NodeView.from(tool); + MetaAccessProvider metaAccess = tool.getMetaAccess(); + ValueNode curValue = getValue(); + ValueNode newNode = findSynonym(curValue, (AbstractPointerStamp) stamp(view), metaAccess, tool.getConstantReflection()); + if (newNode != null) { + return newNode; } return this; } @@ -112,12 +109,10 @@ public static ValueNode findSynonym(ValueNode curValue, AbstractPointerStamp sta @Override public void virtualize(VirtualizerTool tool) { - if (!GeneratePIC.getValue(tool.getOptions())) { - ValueNode alias = tool.getAlias(getValue()); - TypeReference type = StampTool.typeReferenceOrNull(alias); - if (type != null && type.isExact()) { - tool.replaceWithValue(ConstantNode.forConstant(stamp(NodeView.DEFAULT), tool.getConstantReflection().asObjectHub(type.getType()), tool.getMetaAccess(), graph())); - } + ValueNode alias = tool.getAlias(getValue()); + TypeReference type = StampTool.typeReferenceOrNull(alias); + if (type != null && type.isExact()) { + tool.replaceWithValue(ConstantNode.forConstant(stamp(NodeView.DEFAULT), tool.getConstantReflection().asObjectHub(type.getType()), tool.getMetaAccess(), graph())); } } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java index 3faf761c980f..21f5e1403c05 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java @@ -178,14 +178,14 @@ public Node canonical(CanonicalizerTool tool) { if (offset().isConstant() && targetObject.isConstant() && !targetObject.isNullConstant()) { ConstantNode objectConstant = (ConstantNode) targetObject; ResolvedJavaType type = StampTool.typeOrNull(objectConstant); - if (type != null && type.isArray()) { - JavaConstant arrayConstant = objectConstant.asJavaConstant(); - if (arrayConstant != null) { + if (type != null) { + JavaConstant javaConstant = objectConstant.asJavaConstant(); + if (javaConstant != null) { int stableDimension = objectConstant.getStableDimension(); - if (stableDimension > 0) { + if (locationIdentity.isImmutable() || (type.isArray() && stableDimension > 0)) { NodeView view = NodeView.from(tool); long constantOffset = offset().asJavaConstant().asLong(); - Constant constant = stamp(view).readConstant(tool.getConstantReflection().getMemoryAccessProvider(), arrayConstant, constantOffset); + Constant constant = stamp(view).readConstant(tool.getConstantReflection().getMemoryAccessProvider(), javaConstant, constantOffset); boolean isDefaultStable = objectConstant.isDefaultStable(); if (constant != null && (isDefaultStable || !constant.isDefaultForKind())) { /* @@ -199,7 +199,7 @@ public Node canonical(CanonicalizerTool tool) { * accesses for building the AST during PE, and should not enforce * ordering on language side accesses. */ - return ConstantNode.forConstant(stamp(view), constant, stableDimension - 1, isDefaultStable, tool.getMetaAccess()); + return ConstantNode.forConstant(stamp(view), constant, Math.max(stableDimension - 1, 0), isDefaultStable, tool.getMetaAccess()); } } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnboxNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnboxNode.java index 35dcb908bec3..883ac62796e4 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnboxNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnboxNode.java @@ -29,13 +29,13 @@ import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.Canonicalizable; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodeinfo.InputType; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.FieldLocationIdentity; import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.Canonicalizable; +import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.Virtualizable; import org.graalvm.compiler.nodes.spi.VirtualizerTool; @@ -49,7 +49,7 @@ import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaType; -@NodeInfo(cycles = CYCLES_2, size = SIZE_16, allowedUsageTypes = {InputType.Memory, InputType.Value}) +@NodeInfo(cycles = CYCLES_2, size = SIZE_16, allowedUsageTypes = {InputType.Value}) public final class UnboxNode extends AbstractBoxingNode implements Virtualizable, Lowerable, Canonicalizable.Unary { public static final NodeClass TYPE = NodeClass.create(UnboxNode.class); diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/BarrierSet.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/BarrierSet.java index 78f687583b79..fa6ba10cad1a 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/BarrierSet.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/BarrierSet.java @@ -48,4 +48,13 @@ public interface BarrierSet { BarrierType arrayStoreBarrierType(JavaKind storageKind); BarrierType guessStoreBarrierType(ValueNode object, ValueNode value); + + /** + * Determine whether writes of the given {@code storageKind} may ever need a pre-write barrier. + * + * @return {@code false} if no writes of {@code storageKind} ever need a pre-write barrier; + * {@code true} if writes of {@code storageKind} may need a pre-write barrier at least + * under certain circumstances. + */ + boolean mayNeedPreWriteBarrier(JavaKind storageKind); } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/CardTableBarrierSet.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/CardTableBarrierSet.java index f29782ba2981..0c69c2077764 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/CardTableBarrierSet.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/CardTableBarrierSet.java @@ -27,6 +27,7 @@ import org.graalvm.compiler.core.common.type.AbstractObjectStamp; import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; @@ -211,7 +212,7 @@ private static boolean hasWriteBarrier(FixedAccessNode node) { } private static boolean hasWriteBarrier(ArrayRangeWrite write) { - FixedAccessNode node = write.asNode(); + FixedWithNextNode node = write.asFixedWithNextNode(); return node.next() instanceof SerialArrayRangeWriteBarrier && matches(write, (SerialArrayRangeWriteBarrier) node.next()); } @@ -238,4 +239,9 @@ private static boolean matches(FixedAccessNode node, SerialWriteBarrier barrier) private static boolean matches(ArrayRangeWrite node, SerialArrayRangeWriteBarrier barrier) { return barrier.getAddress() == node.getAddress() && node.getLength() == barrier.getLength() && node.getElementStride() == barrier.getElementStride(); } + + @Override + public boolean mayNeedPreWriteBarrier(JavaKind storageKind) { + return false; + } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/G1BarrierSet.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/G1BarrierSet.java index c3d35dd38eff..b5338cfd7c89 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/G1BarrierSet.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/G1BarrierSet.java @@ -201,4 +201,9 @@ private static void addG1PostWriteBarrier(FixedAccessNode node, AddressNode addr private static boolean isObjectValue(ValueNode value) { return value.stamp(NodeView.DEFAULT) instanceof AbstractObjectStamp; } + + @Override + public boolean mayNeedPreWriteBarrier(JavaKind storageKind) { + return arrayStoreBarrierType(storageKind) != BarrierType.NONE; + } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java index 4bf7c471c24e..97660444bc13 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java @@ -42,8 +42,6 @@ public static class Plugins { private TypePlugin[] typePlugins; private InlineInvokePlugin[] inlineInvokePlugins; private ClassInitializationPlugin classInitializationPlugin; - private InvokeDynamicPlugin invokeDynamicPlugin; - private ProfilingPlugin profilingPlugin; /** * Creates a copy of a given set of plugins. The {@link InvocationPlugins} in @@ -57,8 +55,6 @@ public Plugins(Plugins copyFrom, InvocationPlugins invocationPlugins) { this.typePlugins = copyFrom.typePlugins; this.inlineInvokePlugins = copyFrom.inlineInvokePlugins; this.classInitializationPlugin = copyFrom.classInitializationPlugin; - this.invokeDynamicPlugin = copyFrom.invokeDynamicPlugin; - this.profilingPlugin = copyFrom.profilingPlugin; } public Plugins(Plugins copyFrom) { @@ -167,22 +163,6 @@ public void setClassInitializationPlugin(ClassInitializationPlugin plugin) { this.classInitializationPlugin = plugin; } - public InvokeDynamicPlugin getInvokeDynamicPlugin() { - return invokeDynamicPlugin; - } - - public void setInvokeDynamicPlugin(InvokeDynamicPlugin plugin) { - this.invokeDynamicPlugin = plugin; - } - - public ProfilingPlugin getProfilingPlugin() { - return profilingPlugin; - } - - public void setProfilingPlugin(ProfilingPlugin plugin) { - this.profilingPlugin = plugin; - } - public StampPair getOverridingStamp(GraphBuilderTool b, JavaType type, boolean nonNull) { for (TypePlugin plugin : getTypePlugins()) { StampPair stamp = plugin.interceptType(b, type, nonNull); diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java index d1f3122b2188..c0c5ca233aab 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java @@ -43,19 +43,24 @@ import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.DynamicPiNode; +import org.graalvm.compiler.nodes.EndNode; import org.graalvm.compiler.nodes.FixedGuardNode; +import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.IfNode; import org.graalvm.compiler.nodes.Invoke; import org.graalvm.compiler.nodes.LogicNode; +import org.graalvm.compiler.nodes.MergeNode; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.PiNode; import org.graalvm.compiler.nodes.PluginReplacementNode; +import org.graalvm.compiler.nodes.PluginReplacementWithExceptionNode; import org.graalvm.compiler.nodes.ProfileData.BranchProbabilityData; import org.graalvm.compiler.nodes.StateSplit; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.IntegerEqualsNode; +import org.graalvm.compiler.nodes.calc.IntegerLessThanNode; import org.graalvm.compiler.nodes.calc.IsNullNode; import org.graalvm.compiler.nodes.calc.NarrowNode; import org.graalvm.compiler.nodes.calc.SignExtendNode; @@ -297,6 +302,8 @@ default boolean isPluginEnabled(GraphBuilderPlugin plugin) { */ IntrinsicContext getIntrinsic(); + boolean isParsingInvocationPlugin(); + BailoutException bailout(String string); default ValueNode nullCheckedValue(ValueNode value) { @@ -308,6 +315,7 @@ default ValueNode nullCheckedValue(ValueNode value) { * since it might be checking a range of indexes for an operation on an array body. */ default GuardingNode intrinsicRangeCheck(LogicNode condition, boolean negated) { + assert isParsingInvocationPlugin(); if (needsExplicitException()) { return emitBytecodeExceptionCheck(condition, negated, BytecodeExceptionKind.INTRINSIC_OUT_OF_BOUNDS); } else { @@ -333,6 +341,28 @@ default ValueNode nullCheckedValue(ValueNode value, DeoptimizationAction action) return value; } + /** + * When {@link #needsExplicitException} is true, the method returns a node with a stamp that is + * always positive and emits code that throws the provided exceptionKind for a negative length. + */ + default ValueNode maybeEmitExplicitNegativeArraySizeCheck(ValueNode arrayLength, BytecodeExceptionKind exceptionKind) { + if (!needsExplicitException() || ((IntegerStamp) arrayLength.stamp(NodeView.DEFAULT)).isPositive()) { + return arrayLength; + } + ConstantNode zero = ConstantNode.defaultForKind(arrayLength.getStackKind()); + LogicNode condition = append(IntegerLessThanNode.create(getConstantReflection(), getMetaAccess(), getOptions(), null, arrayLength, zero, NodeView.DEFAULT)); + ValueNode[] arguments = exceptionKind.getNumArguments() == 1 ? new ValueNode[]{arrayLength} : new ValueNode[0]; + GuardingNode guardingNode = emitBytecodeExceptionCheck(condition, false, exceptionKind, arguments); + if (guardingNode == null) { + return arrayLength; + } + return append(PiNode.create(arrayLength, StampFactory.positiveInt(), guardingNode.asNode())); + } + + default ValueNode maybeEmitExplicitNegativeArraySizeCheck(ValueNode arrayLength) { + return maybeEmitExplicitNegativeArraySizeCheck(arrayLength, BytecodeExceptionKind.NEGATIVE_ARRAY_SIZE); + } + default GuardingNode maybeEmitExplicitDivisionByZeroCheck(ValueNode divisor) { if (!needsExplicitException() || !((IntegerStamp) divisor.stamp(NodeView.DEFAULT)).contains(0)) { return null; @@ -381,14 +411,14 @@ default void genCheckcastDynamic(ValueNode object, ValueNode javaClass) { } /** - * Some {@link InvocationPlugin InvocationPlugins} have to build a - * {@link org.graalvm.compiler.nodes.MergeNode} to handle multiple return paths but not all - * contexts can do this. + * Some {@link InvocationPlugin InvocationPlugins} have to build a {@link MergeNode} to handle + * multiple return paths but not all contexts can do this. * - * @return false if {@link #getIntrinsicReturnState(JavaKind, ValueNode)} cannot be called (i.e. - * it unconditionally raises an error) + * @return false if {@link #getInvocationPluginReturnState(JavaKind, ValueNode)} cannot be + * called (i.e. it unconditionally raises an error) */ default boolean canMergeIntrinsicReturns() { + assert isParsingInvocationPlugin(); return false; } @@ -397,16 +427,29 @@ default boolean canMergeIntrinsicReturns() { * the top of stack. Usually this will be a state in the caller after the call site. */ @SuppressWarnings("unused") - default FrameState getIntrinsicReturnState(JavaKind returnKind, ValueNode returnValue) { + default FrameState getInvocationPluginReturnState(JavaKind returnKind, ValueNode returnValue) { + throw new GraalError("Cannot be called on a " + getClass().getName() + " object"); + } + + /** + * Build a FrameState that represents the represents the state before an intrinsic was invoked. + */ + @SuppressWarnings("all") + default FrameState getInvocationPluginBeforeState() { throw new GraalError("Cannot be called on a " + getClass().getName() + " object"); } /** - * When this returns true, the parser will report an error if an {@link InvocationPlugin} + * When this returns false, the parser will report an error if an {@link InvocationPlugin} * inserts a {@link org.graalvm.compiler.nodes.DeoptimizeNode} or {@link FixedGuardNode}. */ - default boolean disallowDeoptInPlugins() { - return StrictDeoptInsertionChecks.getValue(getOptions()); + default boolean allowDeoptInPlugins() { + return !StrictDeoptInsertionChecks.getValue(getOptions()); + } + + @SuppressWarnings("all") + default Invoke invokeFallback(FixedWithNextNode predecessor, EndNode end) { + throw new GraalError("Cannot be called on a " + getClass().getName() + " object"); } /** @@ -466,15 +509,36 @@ default AbstractBeginNode genExplicitExceptionEdge(BytecodeExceptionKind excepti } /** + * Replaces an invocation of a given method by inserting a {@link PluginReplacementNode} that + * {@linkplain GraphBuilderContext#shouldDeferPlugin defers} the application of an + * {@link InvocationPlugin}. * - * @param plugin - * @param targetMethod - * @param args - * @param replacementFunction + * @param plugin the {@link InvocationPlugin} that is deferred + * @param targetMethod the target of the replacement invocation + * @param args the arguments to the replacement invocation + * @param replacementFunction the replacement function for deferred application of the + * {@code plugin} */ default void replacePlugin(GeneratedInvocationPlugin plugin, ResolvedJavaMethod targetMethod, ValueNode[] args, PluginReplacementNode.ReplacementFunction replacementFunction) { throw GraalError.unimplemented(); } + + /** + * Replaces an invocation of a given method by inserting a + * {@link PluginReplacementWithExceptionNode} that + * {@linkplain GraphBuilderContext#shouldDeferPlugin defers} the application of an + * {@link InvocationPlugin}. + * + * @param plugin the {@link InvocationPlugin} that is deferred + * @param targetMethod the target of the replacement invocation + * @param args the arguments to the replacement invocation + * @param replacementFunction the replacement function for deferred application of the + * {@code plugin} + */ + default void replacePluginWithException(GeneratedInvocationPlugin plugin, ResolvedJavaMethod targetMethod, ValueNode[] args, + PluginReplacementWithExceptionNode.ReplacementWithExceptionFunction replacementFunction) { + throw GraalError.unimplemented(); + } } class GraphBuilderContextUtil { diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugin.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugin.java index 6515a300ea49..eb9a5e8a944b 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugin.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugin.java @@ -24,6 +24,8 @@ */ package org.graalvm.compiler.nodes.graphbuilderconf; +import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; + import java.lang.reflect.Method; import org.graalvm.compiler.debug.GraalError; @@ -222,6 +224,9 @@ default String getSourceLocation() { return String.format("%s.%s()", m.getClass().getName(), m.getName()); } } + if (IS_IN_NATIVE_IMAGE) { + return String.format("%s.%s()", c.getName(), "apply"); + } throw new GraalError("could not find method named \"apply\" or \"defaultHandler\" in " + c.getName()); } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ProfilingPlugin.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPluginContext.java similarity index 57% rename from compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ProfilingPlugin.java rename to compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPluginContext.java index e1e132fd5712..6702092bed53 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ProfilingPlugin.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPluginContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,18 +24,32 @@ */ package org.graalvm.compiler.nodes.graphbuilderconf; -import org.graalvm.compiler.nodes.FrameState; -import org.graalvm.compiler.nodes.LogicNode; +import org.graalvm.compiler.nodes.CallTargetNode; +import org.graalvm.compiler.nodes.ValueNode; +import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; -public interface ProfilingPlugin extends GraphBuilderPlugin { - boolean shouldProfile(GraphBuilderContext builder, ResolvedJavaMethod method); +public class InvocationPluginContext { - void profileInvoke(GraphBuilderContext builder, ResolvedJavaMethod method, FrameState frameState); + public final CallTargetNode.InvokeKind invokeKind; + public final ValueNode[] args; + public final JavaKind resultType; + /** + * Plugin current being processed. + */ + public final InvocationPlugin plugin; - void profileGoto(GraphBuilderContext builder, ResolvedJavaMethod method, int bci, int targetBci, FrameState frameState); - - void profileIf(GraphBuilderContext builder, ResolvedJavaMethod method, int bci, LogicNode condition, int trueBranchBci, int falseBranchBci, FrameState frameState); + /** + * Method being intrinsified. + */ + public final ResolvedJavaMethod targetMethod; + public InvocationPluginContext(CallTargetNode.InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, InvocationPlugin plugin) { + this.invokeKind = invokeKind; + this.args = args; + this.resultType = resultType; + this.plugin = plugin; + this.targetMethod = targetMethod; + } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvokeDynamicPlugin.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvokeDynamicPlugin.java deleted file mode 100644 index 11ebe26e02b3..000000000000 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvokeDynamicPlugin.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.nodes.graphbuilderconf; - -import org.graalvm.compiler.nodes.FrameState; -import org.graalvm.compiler.nodes.ValueNode; - -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.JavaConstant; - -/** - * {@link GraphBuilderPlugin} interface for static compilation mode, allowing references to dynamic - * types. - */ -public interface InvokeDynamicPlugin extends GraphBuilderPlugin { - - /** - * Checks for a resolved dynamic adapter method at the specified index, resulting from either a - * resolved invokedynamic or invokevirtual on a signature polymorphic MethodHandle method - * (HotSpot invokehandle). - * - * @param builder context for the invoke - * @param cpi the constant pool index - * @param opcode the opcode of the instruction for which the lookup is being performed - * @return {@code true} if a signature polymorphic method reference was found, otherwise - * {@code false} - */ - boolean isResolvedDynamicInvoke(GraphBuilderContext builder, int cpi, int opcode); - - /** - * Checks if this plugin instance supports the specified dynamic invoke. - * - * @param builder context for the invoke - * @param cpi the constant pool index - * @param opcode the opcode of the invoke instruction - * @return {@code true} if this dynamic invoke is supported - */ - boolean supportsDynamicInvoke(GraphBuilderContext builder, int cpi, int opcode); - - /** - * Notifies this object of the value and context of the dynamic method target (e.g., A HotSpot - * adapter method) for a resolved dynamic invoke. - * - * @param builder context for the invoke - * @param cpi the constant pool index - * @param opcode the opcode of the instruction for which the lookup is being performed - * @param target dynamic target method to record - */ - void recordDynamicMethod(GraphBuilderContext builder, int cpi, int opcode, ResolvedJavaMethod target); - - /** - * Notifies this object of the value and context of the dynamic appendix object for a resolved - * dynamic invoke. - * - * @param builder context for the invoke - * @param cpi the constant pool index - * @param opcode the opcode of the instruction for which the lookup is being performed - * @return {@link ValueNode} for appendix constant - */ - ValueNode genAppendixNode(GraphBuilderContext builder, int cpi, int opcode, JavaConstant appendix, FrameState frameState); - -} diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractCompareAndSwapNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractCompareAndSwapNode.java index 37ba1e32ad0d..4c1b321aa450 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractCompareAndSwapNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractCompareAndSwapNode.java @@ -26,6 +26,7 @@ import static org.graalvm.compiler.nodeinfo.InputType.Memory; import static org.graalvm.compiler.nodeinfo.InputType.State; +import static org.graalvm.word.LocationIdentity.any; import org.graalvm.compiler.core.common.memory.MemoryOrderMode; import org.graalvm.compiler.core.common.type.Stamp; @@ -105,6 +106,6 @@ public Stamp getAccessStamp(NodeView view) { @Override public LocationIdentity getKilledLocationIdentity() { - return getLocationIdentity(); + return any(); } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractNewArrayNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractNewArrayNode.java index 1c2359e9bb5d..f0f351abc4a9 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractNewArrayNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractNewArrayNode.java @@ -24,7 +24,6 @@ */ package org.graalvm.compiler.nodes.java; -import jdk.vm.ci.meta.ConstantReflectionProvider; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.NodeInfo; @@ -32,11 +31,13 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.spi.ArrayLengthProvider; +import jdk.vm.ci.meta.ConstantReflectionProvider; + /** * The {@code AbstractNewArrayNode} is used for all 1-dimensional array allocations. */ @NodeInfo -public abstract class AbstractNewArrayNode extends AbstractNewObjectNode implements ArrayLengthProvider { +public abstract class AbstractNewArrayNode extends AbstractNewObjectNode implements ArrayLengthProvider, NewArrayInterface { public static final NodeClass TYPE = NodeClass.create(AbstractNewArrayNode.class); @Input protected ValueNode length; @@ -55,6 +56,11 @@ protected AbstractNewArrayNode(NodeClass c, Stam this.length = length; } + @Override + public final AbstractNewArrayNode asNewArrayNode() { + return this; + } + /** * The list of node which produce input for this instruction. */ diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ClassIsAssignableFromNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ClassIsAssignableFromNode.java index 8bf1ef165636..bfcb40546ce0 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ClassIsAssignableFromNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ClassIsAssignableFromNode.java @@ -30,6 +30,7 @@ import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodes.extended.GetClassNode; import org.graalvm.compiler.nodes.spi.Canonicalizable; import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodeinfo.NodeInfo; @@ -74,6 +75,14 @@ public ValueNode getOtherClass() { @Override public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { + if (forY instanceof GetClassNode) { + // Canonicalize `Class.isAssignableFrom(Object.getClass())` to + // `Class.isInstance(Object)`. + // For non-leaf types, `Object.getClass()` cannot only return a ValueNode stamped + // java.lang.Class, which prevents folding to a isNull check when the Object argument is + // constant and complicates ClassIsAssignableFrom in the other cases. + return InstanceOfDynamicNode.create(tool.getAssumptions(), tool.getConstantReflection(), forX, ((GetClassNode) forY).getObject(), false); + } if (forX.isConstant() && forY.isConstant()) { ConstantReflectionProvider constantReflection = tool.getConstantReflection(); ResolvedJavaType thisType = constantReflection.asJavaType(forX.asJavaConstant()); diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewArrayNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewArrayNode.java index a4acb314df7f..c5de8e936b28 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewArrayNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewArrayNode.java @@ -25,8 +25,6 @@ //JaCoCo Exclude package org.graalvm.compiler.nodes.java; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; - import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.TypeReference; @@ -100,11 +98,6 @@ public JavaKind getKnownElementKind() { @Override public Node canonical(CanonicalizerTool tool) { if (elementType.isConstant()) { - if (GeneratePIC.getValue(tool.getOptions())) { - // Can't fold for AOT, because the resulting NewArrayNode will be missing its - // ResolveConstantNode for the array class. - return this; - } ResolvedJavaType type = tool.getConstantReflection().asJavaType(elementType.asConstant()); if (type != null && !throwsIllegalArgumentException(type) && tool.getMetaAccessExtensionProvider().canConstantFoldDynamicAllocation(type.getArrayClass())) { return createNewArrayNode(type); diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewInstanceNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewInstanceNode.java index 54e370269fe7..b8b47e310c48 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewInstanceNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewInstanceNode.java @@ -24,8 +24,6 @@ */ package org.graalvm.compiler.nodes.java; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; - import java.lang.reflect.Modifier; import org.graalvm.compiler.core.common.type.ObjectStamp; @@ -64,11 +62,6 @@ public ValueNode getInstanceType() { public static boolean canConvertToNonDynamic(ValueNode clazz, CanonicalizerTool tool) { if (clazz.isConstant()) { - if (GeneratePIC.getValue(tool.getOptions())) { - // Can't fold for AOT, because the resulting NewInstanceNode will be missing its - // InitializeKlassNode. - return false; - } ResolvedJavaType type = tool.getConstantReflection().asJavaType(clazz.asConstant()); if (type != null && !throwsInstantiationException(type, tool.getMetaAccess()) && tool.getMetaAccessExtensionProvider().canConstantFoldDynamicAllocation(type)) { return true; diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java index da95b4564547..0c0fdc7f665a 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java @@ -29,6 +29,7 @@ import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.TypeReference; +import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.InputType; @@ -36,10 +37,10 @@ import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.BeginNode; import org.graalvm.compiler.nodes.BeginStateSplitNode; +import org.graalvm.compiler.nodes.DeoptimizingNode; import org.graalvm.compiler.nodes.KillingBeginNode; import org.graalvm.compiler.nodes.MultiKillingBeginNode; import org.graalvm.compiler.nodes.NodeView; -import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.StructuredGraph.FrameStateVerification; import org.graalvm.compiler.nodes.memory.MultiMemoryKill; import org.graalvm.compiler.nodes.memory.SingleMemoryKill; @@ -56,7 +57,7 @@ * throw instruction or implicit exception). */ @NodeInfo(allowedUsageTypes = Memory, cycles = CYCLES_8, size = SIZE_8) -public final class ExceptionObjectNode extends BeginStateSplitNode implements Lowerable, SingleMemoryKill { +public final class ExceptionObjectNode extends BeginStateSplitNode implements Lowerable, SingleMemoryKill, DeoptimizingNode.DeoptAfter { public static final NodeClass TYPE = NodeClass.create(ExceptionObjectNode.class); public ExceptionObjectNode(MetaAccessProvider metaAccess) { @@ -79,7 +80,7 @@ public boolean hasSideEffect() { @Override public void lower(LoweringTool tool) { - if (graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { + if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.LOW_TIER) { /* * Now the lowering to BeginNode+LoadExceptionNode can be performed, since no more * deopts can float in between the begin node and the load exception node. @@ -98,6 +99,8 @@ public void lower(LoweringTool tool) { LoadExceptionObjectNode loadException = graph().add(new LoadExceptionObjectNode(stamp(NodeView.DEFAULT))); + GraalError.guarantee(graph().getGuardsStage().areFrameStatesAtDeopts(), "Should be after FSA %s", this); + GraalError.guarantee(stateAfter() != null, "StateAfter must not be null for %s", this); loadException.setStateAfter(stateAfter()); replaceAtUsages(loadException, InputType.Value); graph().replaceFixedWithFixed(this, entry); @@ -115,4 +118,9 @@ public boolean verify() { "an exception handler's frame state must have only the exception on the stack"); return super.verify(); } + + @Override + public boolean canDeoptimize() { + return true; + } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadExceptionObjectNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadExceptionObjectNode.java index 0dfe859184a8..bc958dfabff7 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadExceptionObjectNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadExceptionObjectNode.java @@ -31,10 +31,11 @@ import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.AbstractStateSplit; +import org.graalvm.compiler.nodes.DeoptimizingNode; import org.graalvm.compiler.nodes.spi.Lowerable; @NodeInfo(cycles = CYCLES_8, size = SIZE_8) -public final class LoadExceptionObjectNode extends AbstractStateSplit implements Lowerable { +public final class LoadExceptionObjectNode extends AbstractStateSplit implements Lowerable, DeoptimizingNode.DeoptAfter { public static final NodeClass TYPE = NodeClass.create(LoadExceptionObjectNode.class); @@ -42,4 +43,8 @@ public LoadExceptionObjectNode(Stamp stamp) { super(TYPE, stamp); } + @Override + public boolean canDeoptimize() { + return true; + } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MethodCallTargetNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MethodCallTargetNode.java index 9c2268ab4e11..463ba585988b 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MethodCallTargetNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MethodCallTargetNode.java @@ -179,7 +179,7 @@ public void simplify(SimplifierTool tool) { } if (invokeKind.isInterface()) { - MethodCallTargetNode result = tryDevirtualizeInterfaceCall(receiver(), targetMethod, profile, graph().getAssumptions(), contextType, this, invoke().asNode()); + MethodCallTargetNode result = tryDevirtualizeInterfaceCall(receiver(), targetMethod, profile, graph().getAssumptions(), contextType, this, invoke().asFixedNode()); assert result == this; } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK11To16.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewArrayInterface.java similarity index 72% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK11To16.java rename to compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewArrayInterface.java index f1dbc16c2979..6bdb1d064a42 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK11To16.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewArrayInterface.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,15 +22,14 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk; +package org.graalvm.compiler.nodes.java; -import java.util.function.BooleanSupplier; +import org.graalvm.compiler.nodes.FixedWithNextNodeInterface; +import org.graalvm.compiler.nodes.ValueNodeInterface; -import org.graalvm.compiler.serviceprovider.JavaVersionUtil; - -public class JDK11To16 implements BooleanSupplier { - @Override - public boolean getAsBoolean() { - return JavaVersionUtil.JAVA_SPEC >= 11 && JavaVersionUtil.JAVA_SPEC <= 16; - } +/** + * See {@link ValueNodeInterface} for details about these node interfaces. + */ +public interface NewArrayInterface extends FixedWithNextNodeInterface { + AbstractNewArrayNode asNewArrayNode(); } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/CountedLoopInfo.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/CountedLoopInfo.java index 9b043b955739..083103a2bc72 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/CountedLoopInfo.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/CountedLoopInfo.java @@ -29,11 +29,14 @@ import static org.graalvm.compiler.nodes.calc.BinaryArithmeticNode.sub; import static org.graalvm.compiler.nodes.loop.MathUtil.unsignedDivBefore; +import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.util.UnsignedLong; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.GuardNode; @@ -41,11 +44,14 @@ import org.graalvm.compiler.nodes.LogicNode; import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.NodeView; +import org.graalvm.compiler.nodes.PiNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.CompareNode; import org.graalvm.compiler.nodes.calc.ConditionalNode; import org.graalvm.compiler.nodes.calc.NegateNode; +import org.graalvm.compiler.nodes.cfg.Block; +import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; import org.graalvm.compiler.nodes.extended.GuardingNode; import org.graalvm.compiler.nodes.loop.InductionVariable.Direction; import org.graalvm.compiler.nodes.util.IntegerHelper; @@ -252,10 +258,44 @@ protected ValueNode maxTripCountNode(boolean assumeLoopEntered, IntegerHelper in // This check is "wide": it looks like min <= max // That's OK even if the loop is strict (`!isLimitIncluded()`) // because in this case, `div` will be zero when min == max - LogicNode noEntryCheck = integerHelper.createCompareNode(max, min, NodeView.DEFAULT); + LogicNode noEntryCheck = graph.addOrUniqueWithInputs(integerHelper.createCompareNode(max, min, NodeView.DEFAULT)); + ValueNode pi = findOrCreatePositivePi(noEntryCheck, div, graph, loop.loopsData().getCFG()); + if (pi != null) { + return pi; + } return graph.addOrUniqueWithInputs(ConditionalNode.create(noEntryCheck, zero, div, NodeView.DEFAULT)); } + /** + * Before creating a {@code ConditionalNode(noEntryCheck, zero, div)} node, check if the graph + * already contains a {@code !noEntryCheck} path dominating this loop, and build or reuse a + * {@link PiNode} there. + * + * @return a new or existing {@link PiNode} already added to the graph or {@code null} + */ + private ValueNode findOrCreatePositivePi(LogicNode noEntryCheck, ValueNode div, StructuredGraph graph, ControlFlowGraph cfg) { + Stamp positiveIntStamp = StampFactory.positiveInt(); + if (!positiveIntStamp.isCompatible(div.stamp(NodeView.DEFAULT))) { + return null; + } + if (cfg.getNodeToBlock().isNew(loop.loopBegin())) { + return null; + } + Block loopBlock = cfg.blockFor(loop.loopBegin()); + for (Node checkUsage : noEntryCheck.usages()) { + if (checkUsage instanceof IfNode) { + IfNode ifCheck = (IfNode) checkUsage; + if (cfg.getNodeToBlock().isNew(ifCheck.falseSuccessor())) { + continue; + } + if (AbstractControlFlowGraph.dominates(cfg.blockFor(ifCheck.falseSuccessor()), loopBlock)) { + return graph.addOrUniqueWithInputs(PiNode.create(div, positiveIntStamp.improveWith(div.stamp(NodeView.DEFAULT)), ifCheck.falseSuccessor())); + } + } + } + return null; + } + /** * Determine if the loop might be entered. Returns {@code false} if we can tell statically that * the loop cannot be entered; returns {@code true} if the loop might possibly be entered, diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DefaultLoopPolicies.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DefaultLoopPolicies.java index d8cf93ae83ea..bb77250f3c1c 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DefaultLoopPolicies.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DefaultLoopPolicies.java @@ -204,7 +204,7 @@ public boolean shouldPartiallyUnroll(LoopEx loop, CoreProviders providers) { int size = Math.max(1, loop.size() - 1 - loop.loopBegin().phis().count()); int unrollFactor = loopBegin.getUnrollFactor(); if (unrollFactor == 1) { - double loopFrequency = loopBegin.loopFrequency(); + double loopFrequency = loop.localLoopFrequency(); if (loopBegin.isSimpleLoop() && loopFrequency < 5.0) { loopBegin.getDebug().log(DebugContext.VERBOSE_LEVEL, "shouldPartiallyUnroll %s frequency too low %s ", loopBegin, loopFrequency); return false; @@ -239,7 +239,7 @@ public boolean shouldPartiallyUnroll(LoopEx loop, CoreProviders providers) { @Override public boolean shouldTryUnswitch(LoopEx loop) { LoopBeginNode loopBegin = loop.loopBegin(); - double loopFrequency = loopBegin.loopFrequency(); + double loopFrequency = loop.localLoopFrequency(); if (loopFrequency <= 1.0) { return false; } @@ -285,7 +285,7 @@ public UnswitchingDecision shouldUnswitch(LoopEx loop, List co int inBranchTotal = branchNodes.count(); CountingClosure stateNodesCount = new CountingClosure(); - double loopFrequency = loop.loopBegin().loopFrequency(); + double loopFrequency = loop.localLoopFrequency(); OptionValues options = loop.loopBegin().getOptions(); int maxDiff = Options.LoopUnswitchTrivial.getValue(options) + (int) (Options.LoopUnswitchFrequencyBoost.getValue(options) * (loopFrequency - 1.0 + phis)); diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedConvertedInductionVariable.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedConvertedInductionVariable.java index 67a9205a5ed5..30e780e5607a 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedConvertedInductionVariable.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedConvertedInductionVariable.java @@ -53,12 +53,12 @@ public Direction direction() { @Override public ValueNode initNode() { - return op(base.initNode()); + return op(base.initNode(), true); } @Override public ValueNode strideNode() { - return op(base.strideNode()); + return op(base.strideNode(), false); } @Override @@ -88,7 +88,7 @@ public ValueNode extremumNode(boolean assumeLoopEntered, Stamp s) { @Override public ValueNode exitValueNode() { - return op(base.exitValueNode()); + return op(base.exitValueNode(), true); } @Override @@ -105,9 +105,13 @@ public long constantExtremum() { public void deleteUnusedNodes() { } - public ValueNode op(ValueNode v) { - boolean zeroExtend = value instanceof ZeroExtendNode; - return IntegerConvertNode.convert(v, stamp, zeroExtend, graph(), NodeView.DEFAULT); + private ValueNode op(ValueNode v, boolean allowZeroExtend) { + return op(v, allowZeroExtend, true); + } + + private ValueNode op(ValueNode v, boolean allowZeroExtend, boolean gvn) { + boolean zeroExtend = allowZeroExtend && value instanceof ZeroExtendNode; + return IntegerConvertNode.convert(v, stamp, zeroExtend, graph(), NodeView.DEFAULT, gvn); } @Override @@ -122,7 +126,11 @@ public InductionVariable copy(InductionVariable newBase, ValueNode newValue) { @Override public ValueNode copyValue(InductionVariable newBase) { - return op(newBase.valueNode()); + return op(newBase.valueNode(), true); } + @Override + public ValueNode copyValue(InductionVariable newBase, boolean gvn) { + return op(newBase.valueNode(), true, gvn); + } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedInductionVariable.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedInductionVariable.java index adb08ee01be5..7e2a54d75aa8 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedInductionVariable.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedInductionVariable.java @@ -51,10 +51,12 @@ public InductionVariable getBase() { @Override public InductionVariable duplicate() { InductionVariable newBase = base.duplicate(); - return copy(newBase, copyValue(newBase)); + return copy(newBase, copyValue(newBase, false/* no gvn */)); } public abstract ValueNode copyValue(InductionVariable newBase); + public abstract ValueNode copyValue(InductionVariable newBase, boolean gvn); + public abstract InductionVariable copy(InductionVariable newBase, ValueNode newValue); } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedOffsetInductionVariable.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedOffsetInductionVariable.java index c530f73189e6..eb94eed1af83 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedOffsetInductionVariable.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedOffsetInductionVariable.java @@ -141,15 +141,19 @@ private long op(long b, long o) { } public ValueNode op(ValueNode b, ValueNode o) { + return op(b, o, true); + } + + public ValueNode op(ValueNode b, ValueNode o, boolean gvn) { if (value instanceof AddNode) { - return add(graph(), b, o); + return add(graph(), b, o, gvn); } if (value instanceof SubNode) { if (base.valueNode() == value.getX()) { - return sub(graph(), b, o); + return sub(graph(), b, o, gvn); } else { assert base.valueNode() == value.getY(); - return sub(graph(), o, b); + return sub(graph(), o, b, gvn); } } throw GraalError.shouldNotReachHere(); @@ -197,7 +201,12 @@ public String toString() { @Override public ValueNode copyValue(InductionVariable newBase) { - return op(newBase.valueNode(), offset); + return copyValue(newBase, true); + } + + @Override + public ValueNode copyValue(InductionVariable newBase, boolean gvn) { + return op(newBase.valueNode(), offset, gvn); } @Override diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedScaledInductionVariable.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedScaledInductionVariable.java index 2ce1afbd55f6..56e28cf51f3e 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedScaledInductionVariable.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedScaledInductionVariable.java @@ -167,9 +167,14 @@ public String toString() { return String.format("DerivedScaleInductionVariable base (%s) %s %s", base, value.getNodeClass().shortName(), scale); } + @Override + public ValueNode copyValue(InductionVariable newBase, boolean gvn) { + return MathUtil.mul(graph(), newBase.valueNode(), scale, gvn); + } + @Override public ValueNode copyValue(InductionVariable newBase) { - return MathUtil.mul(graph(), newBase.valueNode(), scale); + return copyValue(newBase, true); } @Override diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/LoopEx.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/LoopEx.java index b65a33963d51..a2b1ccc42269 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/LoopEx.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/LoopEx.java @@ -57,6 +57,7 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.ValuePhiNode; +import org.graalvm.compiler.nodes.ProfileData.ProfileSource; import org.graalvm.compiler.nodes.calc.AddNode; import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode; import org.graalvm.compiler.nodes.calc.CompareNode; @@ -90,6 +91,14 @@ protected LoopEx(Loop loop, LoopsData data) { this.data = data; } + public double localLoopFrequency() { + return data.getCFG().localLoopFrequency(loopBegin()); + } + + public ProfileSource localFrequencySource() { + return data.getCFG().localLoopFrequencySource(loopBegin()); + } + public Loop loop() { return loop; } @@ -566,4 +575,8 @@ public boolean canStripMine() { } return true; } + + public boolean canBecomeLimitTestAfterFloatingReads(@SuppressWarnings("unused") IfNode ifNode) { + return false; + } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/LoopFragment.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/LoopFragment.java index 99988f4b7a1b..ef350b98ed63 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/LoopFragment.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/LoopFragment.java @@ -31,6 +31,7 @@ import org.graalvm.collections.EconomicMap; import org.graalvm.collections.MapCursor; import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph; +import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Graph; import org.graalvm.compiler.graph.Graph.DuplicationReplacement; import org.graalvm.compiler.graph.Node; @@ -248,7 +249,7 @@ protected static void computeNodes(NodeBitMap nodes, Graph graph, LoopEx loop, I } final NodeBitMap nonLoopNodes = graph.createNodeBitMap(); - Deque worklist = new ArrayDeque<>(); + WorkQueue worklist = new WorkQueue(graph); for (AbstractBeginNode b : blocks) { if (b.isDeleted()) { continue; @@ -307,6 +308,56 @@ public int hashCode() { } } + static class WorkQueue implements Iterable { + Deque worklist; + NodeBitMap contents; + + WorkQueue(Graph graph) { + worklist = new ArrayDeque<>(); + contents = new NodeBitMap(graph); + } + + public void addFirst(WorkListEntry e) { + worklist.addFirst(e); + GraalError.guarantee(!contents.isMarked(e.n), "Trying to addFirst an entry that is already in the work queue!"); + contents.mark(e.n); + } + + public void push(WorkListEntry e) { + worklist.push(e); + GraalError.guarantee(!contents.isMarked(e.n), "Trying to push an entry that is already in the work queue!"); + contents.mark(e.n); + } + + public WorkListEntry peek() { + return worklist.peek(); + } + + public WorkListEntry pop() { + WorkListEntry e = worklist.pop(); + contents.clear(e.n); + return e; + } + + public boolean isEmpty() { + return worklist.isEmpty(); + } + + public boolean contains(WorkListEntry e) { + return contents.contains(e.n); + } + + public void clear() { + worklist.clear(); + contents.clearAll(); + } + + @Override + public Iterator iterator() { + return worklist.iterator(); + } + } + static TriState isLoopNode(Node n, NodeBitMap loopNodes, NodeBitMap nonLoopNodes) { if (loopNodes.isMarked(n)) { return TriState.TRUE; @@ -321,13 +372,13 @@ static TriState isLoopNode(Node n, NodeBitMap loopNodes, NodeBitMap nonLoopNodes return TriState.UNKNOWN; } - private static void pushWorkList(Deque workList, Node node, NodeBitMap loopNodes) { + private static void pushWorkList(WorkQueue workList, Node node, NodeBitMap loopNodes) { WorkListEntry entry = new WorkListEntry(node, loopNodes); - assert !workList.contains(entry) : "node " + node + " added to worklist twice"; + GraalError.guarantee(!workList.contains(entry), "node %s added to worklist twice", node); workList.push(entry); } - private static void markFloating(Deque workList, LoopEx loop, Node start, NodeBitMap loopNodes, NodeBitMap nonLoopNodes) { + private static void markFloating(WorkQueue workList, LoopEx loop, Node start, NodeBitMap loopNodes, NodeBitMap nonLoopNodes) { if (isLoopNode(start, loopNodes, nonLoopNodes).isKnown()) { return; } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/LoopFragmentInside.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/LoopFragmentInside.java index fc7619bd48d2..2bb380b9789d 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/LoopFragmentInside.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/LoopFragmentInside.java @@ -233,7 +233,6 @@ public void insertWithinAfter(LoopEx loop, EconomicMap 0) { - Constant constant = read.stamp(view).readConstant(tool.getConstantReflection().getMemoryAccessProvider(), object.asConstant(), displacement); + Constant constant = read.stamp(view).readConstant(constantReflection.getMemoryAccessProvider(), object.asConstant(), displacement); boolean isDefaultStable = locationIdentity.isImmutable() || ((ConstantNode) object).isDefaultStable(); if (constant != null && (isDefaultStable || !constant.isDefaultForKind())) { return ConstantNode.forConstant(read.stamp(view), constant, Math.max(stableDimension - 1, 0), isDefaultStable, metaAccess); diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringProvider.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringProvider.java index 0d6f17e84f10..dc151a686aea 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringProvider.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringProvider.java @@ -70,4 +70,9 @@ public interface LoweringProvider { */ boolean supportsRounding(); + /** + * Indicates whether this target platform supports the usage of implicit (trapping) null checks. + */ + boolean supportsImplicitNullChecks(); + } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Proxy.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Proxy.java index 05f7a196f050..d40518789adc 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Proxy.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Proxy.java @@ -25,7 +25,7 @@ package org.graalvm.compiler.nodes.spi; import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.NodeInterface; +import org.graalvm.compiler.nodes.ValueNodeInterface; /** * This interface marks nodes whose result is the same as one of their inputs. Such nodes are used @@ -33,7 +33,7 @@ * * For some algorithms it is necessary or advantageous to see through these proxies. */ -public interface Proxy extends NodeInterface { +public interface Proxy extends ValueNodeInterface { Node getOriginalNode(); diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java index 0b5e8c8b7923..33fa9efc4c11 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java @@ -536,7 +536,7 @@ private static void normalizeLoopBegin(LoopBeginNode begin) { for (PhiNode phi : begin.phis().snapshot()) { GraphUtil.checkRedundantPhi(phi); } - for (LoopExitNode exit : begin.loopExits()) { + for (LoopExitNode exit : begin.loopExits().snapshot()) { for (ProxyNode vpn : exit.proxies().snapshot()) { GraphUtil.checkRedundantProxy(vpn); } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/EnsureVirtualizedNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/EnsureVirtualizedNode.java index a23285d9ea71..d846ec7d68ba 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/EnsureVirtualizedNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/EnsureVirtualizedNode.java @@ -29,9 +29,9 @@ import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.GraalGraphError; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.graph.VerificationError; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.AbstractEndNode; import org.graalvm.compiler.nodes.FixedNode; @@ -67,7 +67,7 @@ public void virtualize(VirtualizerTool tool) { if (alias instanceof VirtualObjectNode) { VirtualObjectNode virtual = (VirtualObjectNode) alias; if (virtual instanceof VirtualBoxingNode) { - Throwable exception = new VerificationError("ensureVirtual is not valid for boxing objects: %s", virtual.type().getName()); + Throwable exception = new GraalGraphError("ensureVirtual is not valid for boxing objects: %s", virtual.type().getName()); throw GraphUtil.approxSourceException(this, exception); } if (!localOnly) { @@ -95,7 +95,7 @@ public static void ensureVirtualFailure(Node location, Stamp stamp) { additionalReason = " (must not let virtual object escape at node " + next + ")"; } } - Throwable exception = new VerificationError("Object of type %s should not be materialized%s:", StampTool.typeOrNull(stamp).getName(), additionalReason); + Throwable exception = new GraalGraphError("Object of type %s should not be materialized%s:", StampTool.typeOrNull(stamp).getName(), additionalReason); Node pos; if (location instanceof FixedWithNextNode) { diff --git a/compiler/src/org.graalvm.compiler.options.jdk11/src/org/graalvm/compiler/options/ModuleSupport.java b/compiler/src/org.graalvm.compiler.options.jdk11/src/org/graalvm/compiler/options/ModuleSupport.java index 04a67c8a9616..b2025d468faf 100644 --- a/compiler/src/org.graalvm.compiler.options.jdk11/src/org/graalvm/compiler/options/ModuleSupport.java +++ b/compiler/src/org.graalvm.compiler.options.jdk11/src/org/graalvm/compiler/options/ModuleSupport.java @@ -28,8 +28,6 @@ public class ModuleSupport { - public static final boolean USE_NI_JPMS = Boolean.parseBoolean(System.getenv().get("USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM")); - static Iterable getOptionsLoader() { /* * The Graal module (i.e., jdk.internal.vm.compiler) is loaded by the platform class loader @@ -37,9 +35,6 @@ static Iterable getOptionsLoader() { * As such, we need to start the provider search at the app class loader instead of the * platform class loader. */ - if (USE_NI_JPMS) { - return ServiceLoader.load(ModuleSupport.class.getModule().getLayer(), OptionDescriptors.class); - } return ServiceLoader.load(OptionDescriptors.class, ClassLoader.getSystemClassLoader()); } } diff --git a/compiler/src/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModuleSupport.java b/compiler/src/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModuleSupport.java index e93e35cfc103..6e101bb5cff5 100644 --- a/compiler/src/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModuleSupport.java +++ b/compiler/src/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModuleSupport.java @@ -28,12 +28,6 @@ public class ModuleSupport { - public static final boolean USE_NI_JPMS; - - static { - USE_NI_JPMS = false; - } - static Iterable getOptionsLoader() { // On JDK 8, Graal and its extensions are loaded by the same class loader. return ServiceLoader.load(OptionDescriptors.class, OptionDescriptors.class.getClassLoader()); diff --git a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java index 75691ae9c145..12d16801dd20 100644 --- a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java +++ b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java @@ -190,7 +190,7 @@ protected void run(StructuredGraph graph, CoreProviders context) { cfg.visitDominatorTree(new MoveGuardsUpwards(), graph.isBeforeStage(StageFlag.VALUE_PROXY_REMOVAL)); } try (DebugContext.Scope scheduleScope = graph.getDebug().scope(SchedulePhase.class)) { - SchedulePhase.run(graph, SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER, cfg); + SchedulePhase.run(graph, SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER, cfg, context, false); } catch (Throwable t) { throw graph.getDebug().handle(t); } diff --git a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java index 7180e65fc88e..da3e25601d27 100644 --- a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java +++ b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java @@ -77,7 +77,6 @@ import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.BasePhase; -import org.graalvm.compiler.phases.Phase; import org.graalvm.compiler.phases.common.util.EconomicSetNodeEventListener; import org.graalvm.compiler.phases.graph.ScheduledNodeIterator; import org.graalvm.compiler.phases.schedule.SchedulePhase; @@ -104,7 +103,7 @@ public class FixReadsPhase extends BasePhase { private static final CounterKey counterBetterMergedStamps = DebugContext.counter("FixReads_BetterMergedStamp"); protected boolean replaceInputsWithConstants; - protected Phase schedulePhase; + protected BasePhase schedulePhase; protected CanonicalizerPhase canonicalizerPhase; @Override @@ -595,7 +594,7 @@ public void exit(Block b, Integer state) { } - public FixReadsPhase(boolean replaceInputsWithConstants, Phase schedulePhase, CanonicalizerPhase canonicalizerPhase) { + public FixReadsPhase(boolean replaceInputsWithConstants, BasePhase schedulePhase, CanonicalizerPhase canonicalizerPhase) { this.replaceInputsWithConstants = replaceInputsWithConstants; this.schedulePhase = schedulePhase; this.canonicalizerPhase = canonicalizerPhase; @@ -605,7 +604,7 @@ public FixReadsPhase(boolean replaceInputsWithConstants, Phase schedulePhase, Ca @SuppressWarnings("try") protected void run(StructuredGraph graph, CoreProviders context) { assert graph.verify(); - schedulePhase.apply(graph); + schedulePhase.apply(graph, context); ScheduleResult schedule = graph.getLastSchedule(); FixReadsClosure fixReadsClosure = new FixReadsClosure(); EconomicSetNodeEventListener ec = new EconomicSetNodeEventListener(); @@ -642,7 +641,7 @@ protected CharSequence getName() { protected void run(StructuredGraph graph, LowTierContext context) { if (GraalOptions.RawConditionalElimination.getValue(graph.getOptions())) { SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.LATEST, true); - schedulePhase.apply(graph); + schedulePhase.apply(graph, context); ScheduleResult schedule = graph.getLastSchedule(); schedule.getCFG().visitDominatorTree(new RawConditionalEliminationVisitor(graph, schedule, context.getMetaAccess(), replaceInputsWithConstants), false); } diff --git a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/GuardLoweringPhase.java b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/GuardLoweringPhase.java index 94be0fd4a1cc..6b89d95fff98 100644 --- a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/GuardLoweringPhase.java +++ b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/GuardLoweringPhase.java @@ -110,7 +110,7 @@ private void lowerToIf(GuardNode guard) { protected void run(StructuredGraph graph, CoreProviders context) { if (graph.getGuardsStage().allowsFloatingGuards()) { SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER); - schedulePhase.apply(graph); + schedulePhase.apply(graph, context); ScheduleResult schedule = graph.getLastSchedule(); for (Block block : schedule.getCFG().getBlocks()) { diff --git a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java index c0e5d0db99eb..f6d7f30f3eee 100644 --- a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java +++ b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java @@ -111,11 +111,6 @@ public void setGuard(GuardingNode guard) { updateUsagesInterface(this.guard, guard); this.guard = guard; } - - @Override - public ValueNode asNode() { - return this; - } } @Override @@ -190,11 +185,12 @@ public GuardingNode createGuard(FixedNode before, LogicNode condition, Deoptimiz @Override public FixedWithNextNode lastFixedNode() { + GraalError.guarantee(lastFixedNode.isAlive(), "The last fixed node %s was deleted by a previous lowering", lastFixedNode); return lastFixedNode; } private void setLastFixedNode(FixedWithNextNode n) { - assert n.isAlive() : n; + GraalError.guarantee(n.isAlive(), "Cannot add last fixed node %s because it is not alive", n); lastFixedNode = n; } } @@ -370,7 +366,7 @@ public boolean checkContract() { @Override public void run(StructuredGraph graph) { - schedulePhase.apply(graph, false); + schedulePhase.apply(graph, context, false); schedule = graph.getLastSchedule(); schedule.getCFG().computePostdominators(); Block startBlock = schedule.getCFG().getStartBlock(); diff --git a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ProfileCompiledMethodsPhase.java b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ProfileCompiledMethodsPhase.java index b682e26d4ed2..ca34491f7699 100644 --- a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ProfileCompiledMethodsPhase.java +++ b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ProfileCompiledMethodsPhase.java @@ -103,10 +103,8 @@ private static String getProperty(String name, String def) { @Override protected void run(StructuredGraph graph) { - SchedulePhase schedule = new SchedulePhase(graph.getOptions()); - schedule.apply(graph, false); - ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true); + SchedulePhase.runWithoutContextOptimizations(graph, SchedulePhase.getDefaultStrategy(graph.getOptions()), cfg, true); for (Loop loop : cfg.getLoops()) { double loopProbability = cfg.blockFor(loop.getHeader().getBeginNode()).getRelativeFrequency(); if (loopProbability > (1D / Integer.MAX_VALUE)) { @@ -124,7 +122,7 @@ protected void run(StructuredGraph graph) { for (Node node : graph.getNodes()) { if (node instanceof Invoke) { Invoke invoke = (Invoke) node; - DynamicCounterNode.addCounterBefore(GROUP_NAME_INVOKES, invoke.callTarget().targetName(), 1, true, invoke.asNode()); + DynamicCounterNode.addCounterBefore(GROUP_NAME_INVOKES, invoke.callTarget().targetName(), 1, true, invoke.asFixedNode()); } } diff --git a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/SnippetFrameStateAssignment.java b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/SnippetFrameStateAssignment.java index 5d237887cd3d..9f13d8716fb6 100644 --- a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/SnippetFrameStateAssignment.java +++ b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/SnippetFrameStateAssignment.java @@ -43,8 +43,8 @@ import org.graalvm.compiler.nodes.StateSplit; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.LoopInfo; import org.graalvm.compiler.phases.graph.ReentrantNodeIterator; +import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.LoopInfo; import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; /** @@ -155,6 +155,7 @@ protected NodeStateAssignment processNode(FixedNode node, NodeStateAssignment st } nextStateAssignment = NodeStateAssignment.INVALID; } + stateMapping.put(node, nextStateAssignment); } return nextStateAssignment; } diff --git a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java index d5e3e746eb09..b9d984fc8035 100644 --- a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java +++ b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java @@ -41,7 +41,6 @@ import org.graalvm.collections.UnmodifiableEconomicMap; import org.graalvm.collections.UnmodifiableMapCursor; import org.graalvm.compiler.api.replacements.MethodSubstitution; -import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.TypeReference; @@ -372,7 +371,7 @@ public static UnmodifiableEconomicMap inline(Invoke invoke, Structur @SuppressWarnings("try") public static UnmodifiableEconomicMap inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod, String reason, String phase, InlineeReturnAction returnAction) { - FixedNode invokeNode = invoke.asNode(); + FixedNode invokeNode = invoke.asFixedNode(); StructuredGraph graph = invokeNode.graph(); final NodeInputList parameters = invoke.callTarget().arguments(); @@ -553,7 +552,7 @@ private static ValueNode finishInlining(Invoke invoke, StructuredGraph graph, Fi List processedReturns = inlineeReturnAction.processInlineeReturns(returnNodes); - FixedNode invokeNode = invoke.asNode(); + FixedNode invokeNode = invoke.asFixedNode(); FrameState stateAfter = invoke.stateAfter(); invokeNode.replaceAtPredecessor(firstNode); @@ -624,11 +623,6 @@ private static ValueNode finishInlining(Invoke invoke, StructuredGraph graph, Fi // Copy inlined methods from inlinee to caller graph.updateMethods(inlineGraph); - // Update the set of accessed fields - if (GraalOptions.GeneratePIC.getValue(graph.getOptions())) { - graph.updateFields(inlineGraph); - } - if (inlineGraph.hasUnsafeAccess()) { graph.markUnsafeAccess(); } @@ -691,7 +685,7 @@ private static void fixFrameStates(StructuredGraph graph, MergeNode originalMerg @SuppressWarnings("try") private static void updateSourcePositions(Invoke invoke, StructuredGraph inlineGraph, UnmodifiableEconomicMap duplicates, boolean isSub, Mark mark) { - FixedNode invokeNode = invoke.asNode(); + FixedNode invokeNode = invoke.asFixedNode(); StructuredGraph invokeGraph = invokeNode.graph(); if (invokeGraph.trackNodeSourcePosition() && invoke.stateAfter() != null) { boolean isSubstitution = isSub || inlineGraph.isSubstitution(); @@ -926,7 +920,7 @@ public static FrameState handleMissingAfterExceptionFrameState(FrameState nonRep workList.add(usage); } else { StateSplit stateSplit = (StateSplit) usage; - FixedNode fixedStateSplit = stateSplit.asNode(); + FixedNode fixedStateSplit = stateSplit.asFixedNode(); if (fixedStateSplit instanceof AbstractMergeNode) { AbstractMergeNode merge = (AbstractMergeNode) fixedStateSplit; while (merge.isAlive()) { @@ -1030,7 +1024,7 @@ public static ValueNode nonNullReceiver(Invoke invoke) { LogicNode condition = graph.unique(IsNullNode.create(newReceiver)); FixedGuardNode fixedGuard = graph.add(new FixedGuardNode(condition, NullCheckException, InvalidateReprofile, true)); PiNode nonNullReceiver = graph.unique(new PiNode(newReceiver, StampFactory.objectNonNull(), fixedGuard)); - graph.addBeforeFixed(invoke.asNode(), fixedGuard); + graph.addBeforeFixed(invoke.asFixedNode(), fixedGuard); newReceiver = nonNullReceiver; } } diff --git a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/MultiTypeGuardInlineInfo.java b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/MultiTypeGuardInlineInfo.java index 20b28966641f..eb33785bd66b 100644 --- a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/MultiTypeGuardInlineInfo.java +++ b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/MultiTypeGuardInlineInfo.java @@ -343,7 +343,7 @@ private EconomicSet inlineSingleMethod(StructuredGraph graph, StampProvide AbstractBeginNode[] successors = new AbstractBeginNode[]{calleeEntryNode, unknownTypeSux}; createDispatchOnTypeBeforeInvoke(graph, successors, false, stampProvider, constantReflection); - calleeEntryNode.setNext(invoke.asNode()); + calleeEntryNode.setNext(invoke.asFixedNode()); return inline(invoke, methodAt(0), inlineableElementAt(0), false, reason); } @@ -385,7 +385,7 @@ private static AbstractBeginNode createInvocationBlock(StructuredGraph graph, In PhiNode exceptionObjectPhi, boolean useForInlining) { Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining); AbstractBeginNode calleeEntryNode = graph.add(new BeginNode()); - calleeEntryNode.setNext(duplicatedInvoke.asNode()); + calleeEntryNode.setNext(duplicatedInvoke.asFixedNode()); EndNode endNode = graph.add(new EndNode()); duplicatedInvoke.setNext(endNode); @@ -465,7 +465,7 @@ private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, AbstractBeginNode[] successors = new AbstractBeginNode[]{invocationEntry, unknownTypeSux}; createDispatchOnTypeBeforeInvoke(graph, successors, true, stampProvider, constantReflection); - invocationEntry.setNext(invoke.asNode()); + invocationEntry.setNext(invoke.asFixedNode()); ValueNode receiver = ((MethodCallTargetNode) invoke.callTarget()).receiver(); PiNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, invocationEntry, target.getDeclaringClass(), receiver, false); invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver); diff --git a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/TypeGuardInlineInfo.java b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/TypeGuardInlineInfo.java index c8090b0b5803..fe2c4dbdf5da 100644 --- a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/TypeGuardInlineInfo.java +++ b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/TypeGuardInlineInfo.java @@ -130,7 +130,7 @@ private void createGuard(StructuredGraph graph, CoreProviders providers) { ValueNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, guard, type, nonNullReceiver, true); invoke.callTarget().replaceFirstInput(nonNullReceiver, anchoredReceiver); - graph.addBeforeFixed(invoke.asNode(), guard); + graph.addBeforeFixed(invoke.asFixedNode(), guard); } } diff --git a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java index fc9bbf75c2f4..b98095956d63 100644 --- a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java +++ b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java @@ -224,7 +224,7 @@ public Iterable getInvokes() { @Override public double getProbability(Invoke invoke) { - return probabilites.applyAsDouble(invoke.asNode()); + return probabilites.applyAsDouble(invoke.asFixedNode()); } public StructuredGraph getGraph() { diff --git a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java index 7d8d482db5a8..01adf2d30fb9 100644 --- a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java +++ b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java @@ -207,7 +207,7 @@ public void computeProbabilities() { } public double invokeProbability(Invoke invoke) { - return probability * probabilities.applyAsDouble(invoke.asNode()); + return probability * probabilities.applyAsDouble(invoke.asFixedNode()); } public double invokeRelevance(Invoke invoke) { diff --git a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/ComputeInliningRelevance.java b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/ComputeInliningRelevance.java index 0bbc31a1409e..5ab1b0f3479b 100644 --- a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/ComputeInliningRelevance.java +++ b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/ComputeInliningRelevance.java @@ -109,7 +109,7 @@ public double getRelevance(Invoke invoke) { return rootScope.computeInvokeRelevance(invoke); } assert nodeRelevances != null : "uninitialized relevance"; - return nodeRelevances.get(invoke.asNode()); + return nodeRelevances.get(invoke.asFixedNode()); } /** @@ -243,7 +243,7 @@ public void process(NodeWorkList workList) { * scope's fastPathMinProbability, adjusted by scopeRelevanceWithinParent. */ public double computeInvokeRelevance(Invoke invoke) { - double invokeProbability = nodeProbabilities.applyAsDouble(invoke.asNode()); + double invokeProbability = nodeProbabilities.applyAsDouble(invoke.asFixedNode()); assert !Double.isNaN(invokeProbability); double relevance = (invokeProbability / getFastPathMinProbability()) * Math.min(1.0, getScopeRelevanceWithinParent()); diff --git a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/LoopUtility.java b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/LoopUtility.java index 92c2942525ce..48d9637b74ba 100644 --- a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/LoopUtility.java +++ b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/LoopUtility.java @@ -41,27 +41,34 @@ public class LoopUtility { /** * Remove loop proxies that became obsolete over time, i.e., they proxy a value that already * flowed out of a loop and dominates the loop now. + * + * @param canonicalizer must not be {@code null}, will be applied incrementally to nodes whose + * inputs changed */ + @SuppressWarnings("try") public static void removeObsoleteProxies(StructuredGraph graph, CoreProviders context, CanonicalizerPhase canonicalizer) { LoopsData loopsData = context.getLoopsDataProvider().getLoopsData(graph); - for (LoopEx loop : loopsData.loops()) { - removeObsoleteProxiesForLoop(loop, context, canonicalizer); + final EconomicSetNodeEventListener inputChanges = new EconomicSetNodeEventListener(EnumSet.of(NodeEvent.INPUT_CHANGED)); + try (NodeEventScope s = graph.trackNodeEvents(inputChanges)) { + for (LoopEx loop : loopsData.loops()) { + removeObsoleteProxiesForLoop(loop); + } } + canonicalizer.applyIncremental(graph, context, inputChanges.getNodes()); } - @SuppressWarnings("try") - public static void removeObsoleteProxiesForLoop(LoopEx loop, CoreProviders context, CanonicalizerPhase canonicalizer) { - StructuredGraph graph = loop.loopBegin().graph(); - final EconomicSetNodeEventListener inputChanges = new EconomicSetNodeEventListener(EnumSet.of(NodeEvent.INPUT_CHANGED)); - try (NodeEventScope s = graph.trackNodeEvents(inputChanges)) { - for (LoopExitNode lex : loop.loopBegin().loopExits()) { - for (ProxyNode proxy : lex.proxies().snapshot()) { - if (loop.isOutsideLoop(proxy.value())) { - proxy.replaceAtUsagesAndDelete(proxy.getOriginalNode()); - } + /** + * Remove obsolete proxies from one loop only. Unlike + * {@link #removeObsoleteProxies(StructuredGraph, CoreProviders, CanonicalizerPhase)}, this does + * not apply canonicalization. + */ + public static void removeObsoleteProxiesForLoop(LoopEx loop) { + for (LoopExitNode lex : loop.loopBegin().loopExits()) { + for (ProxyNode proxy : lex.proxies().snapshot()) { + if (loop.isOutsideLoop(proxy.value())) { + proxy.replaceAtUsagesAndDelete(proxy.getOriginalNode()); } } } - canonicalizer.applyIncremental(graph, context, inputChanges.getNodes()); } } diff --git a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java index e5035282a2a7..8f605e75d2a3 100644 --- a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java +++ b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java @@ -184,7 +184,7 @@ protected boolean shouldDumpAfterAtBasicLevel() { } @SuppressWarnings("try") - protected final void apply(final StructuredGraph graph, final C context, final boolean dumpGraph) { + public final void apply(final StructuredGraph graph, final C context, final boolean dumpGraph) { if (ExcludePhaseFilter.exclude(graph.getOptions(), this, graph.asJavaMethod())) { return; } diff --git a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/NodeCostUtil.java b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/NodeCostUtil.java index f1a1a86b0deb..57b02c264ef4 100644 --- a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/NodeCostUtil.java +++ b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/NodeCostUtil.java @@ -31,8 +31,8 @@ import org.graalvm.compiler.core.common.cfg.BlockMap; import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.graph.GraalGraphError; import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.VerificationError; import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.cfg.Block; @@ -71,8 +71,7 @@ public static double computeGraphCycles(StructuredGraph graph, boolean fullSched Function> blockToNodes; ControlFlowGraph cfg; if (fullSchedule) { - SchedulePhase schedule = new SchedulePhase(SchedulePhase.SchedulingStrategy.LATEST_OUT_OF_LOOPS, true); - schedule.apply(graph); + SchedulePhase.runWithoutContextOptimizations(graph, SchedulePhase.SchedulingStrategy.LATEST_OUT_OF_LOOPS, true); cfg = graph.getLastSchedule().getCFG(); blockToNodes = b -> graph.getLastSchedule().getBlockToNodesMap().get(b); } else { @@ -129,7 +128,7 @@ public static void phaseFulfillsSizeContract(StructuredGraph graph, int codeSize if (deltaCompare(codeSizeAfter, codeSizeBefore * codeSizeIncrease, graphSizeDelta) > 0) { ResolvedJavaMethod method = graph.method(); double increase = (double) codeSizeAfter / (double) codeSizeBefore; - throw new VerificationError("Phase %s expects to increase code size by at most a factor of %.2f but an increase of %.2f was seen (code size before: %d, after: %d)%s", + throw new GraalGraphError("Phase %s expects to increase code size by at most a factor of %.2f but an increase of %.2f was seen (code size before: %d, after: %d)%s", contract.contractorName(), codeSizeIncrease, increase, codeSizeBefore, codeSizeAfter, method != null ? " when compiling method " + method.format("%H.%n(%p)") + "." : "."); } diff --git a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeRelativeFrequencyCache.java b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeRelativeFrequencyCache.java index 55b090988e88..e8981b2caf8e 100644 --- a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeRelativeFrequencyCache.java +++ b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeRelativeFrequencyCache.java @@ -42,6 +42,7 @@ import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.StartNode; +import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; /** * Compute relative frequencies for fixed nodes on the fly and cache them at @@ -101,10 +102,12 @@ public double applyAsDouble(FixedNode node) { return cachedValue; } + ControlFlowGraph cfg = ControlFlowGraph.compute(node.graph(), false, false, false, false); + double relativeFrequency = 0.0; if (current.predecessor() == null) { if (current instanceof AbstractMergeNode) { - relativeFrequency = handleMerge(current, relativeFrequency); + relativeFrequency = handleMerge(current, relativeFrequency, cfg); } else { assert current instanceof StartNode; relativeFrequency = 1D; @@ -118,7 +121,7 @@ public double applyAsDouble(FixedNode node) { return relativeFrequency; } - private double handleMerge(FixedNode current, double relativeFrequency) { + private double handleMerge(FixedNode current, double relativeFrequency, ControlFlowGraph cfg) { double result = relativeFrequency; AbstractMergeNode currentMerge = (AbstractMergeNode) current; NodeInputList currentForwardEnds = currentMerge.forwardEnds(); @@ -130,7 +133,7 @@ private double handleMerge(FixedNode current, double relativeFrequency) { result += applyAsDouble(endNode); } if (current instanceof LoopBeginNode) { - result = multiplyRelativeFrequencies(result, ((LoopBeginNode) current).loopFrequency()); + result = multiplyRelativeFrequencies(result, cfg.localLoopFrequency(((LoopBeginNode) current))); } return result; } diff --git a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/PostOrderNodeIterator.java b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/PostOrderNodeIterator.java index 43c857446256..7268ce52b7a7 100644 --- a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/PostOrderNodeIterator.java +++ b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/PostOrderNodeIterator.java @@ -237,7 +237,7 @@ protected Set controlSplit(ControlSplitNode controlSplit) { } protected void invoke(Invoke invoke) { - node(invoke.asNode()); + node(invoke.asFixedNode()); } protected void finished() { diff --git a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/SinglePassNodeIterator.java b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/SinglePassNodeIterator.java index b70402ca65a4..9eb4df19d1d8 100644 --- a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/SinglePassNodeIterator.java +++ b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/SinglePassNodeIterator.java @@ -367,7 +367,7 @@ protected void controlSplit(ControlSplitNode controlSplit) { } protected void invoke(Invoke invoke) { - node(invoke.asNode()); + node(invoke.asFixedNode()); } /** diff --git a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java index ce14a1970e53..4b3667f07091 100644 --- a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java +++ b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java @@ -85,12 +85,13 @@ import org.graalvm.compiler.nodes.memory.FloatingReadNode; import org.graalvm.compiler.nodes.memory.MultiMemoryKill; import org.graalvm.compiler.nodes.memory.SingleMemoryKill; +import org.graalvm.compiler.nodes.spi.CoreProviders; import org.graalvm.compiler.nodes.spi.ValueProxy; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.phases.Phase; +import org.graalvm.compiler.phases.BasePhase; import org.graalvm.word.LocationIdentity; -public final class SchedulePhase extends Phase { +public final class SchedulePhase extends BasePhase { public enum SchedulingStrategy { EARLIEST_WITH_GUARD_ORDER, @@ -125,7 +126,7 @@ public SchedulePhase(OptionValues options) { } public SchedulePhase(boolean immutableGraph, OptionValues options) { - this(OptScheduleOutOfLoops.getValue(options) ? SchedulingStrategy.LATEST_OUT_OF_LOOPS : SchedulingStrategy.LATEST, immutableGraph); + this(getDefaultStrategy(options), immutableGraph); } public SchedulePhase(SchedulingStrategy strategy) { @@ -137,6 +138,10 @@ public SchedulePhase(SchedulingStrategy strategy, boolean immutableGraph) { this.immutableGraph = immutableGraph; } + public static SchedulingStrategy getDefaultStrategy(OptionValues options) { + return OptScheduleOutOfLoops.getValue(options) ? SchedulingStrategy.LATEST_OUT_OF_LOOPS : SchedulingStrategy.LATEST; + } + private NodeEventScope verifyImmutableGraph(StructuredGraph graph) { if (immutableGraph && Assertions.assertionsEnabled()) { return graph.trackNodeEvents(new NodeEventListener() { @@ -152,16 +157,33 @@ public void changed(NodeEvent e, Node node) { @Override @SuppressWarnings("try") - protected void run(StructuredGraph graph) { + protected void run(StructuredGraph graph, CoreProviders context) { try (NodeEventScope scope = verifyImmutableGraph(graph)) { - Instance inst = new Instance(); + Instance inst = new Instance(context.getLowerer().supportsImplicitNullChecks()); inst.run(graph, selectedStrategy, immutableGraph); } } - public static void run(StructuredGraph graph, SchedulingStrategy strategy, ControlFlowGraph cfg) { - Instance inst = new Instance(cfg); - inst.run(graph, strategy, false); + public static void runWithoutContextOptimizations(StructuredGraph graph) { + runWithoutContextOptimizations(graph, getDefaultStrategy(graph.getOptions())); + } + + public static void runWithoutContextOptimizations(StructuredGraph graph, SchedulingStrategy strategy) { + runWithoutContextOptimizations(graph, strategy, ControlFlowGraph.computeForSchedule(graph), false); + } + + public static void runWithoutContextOptimizations(StructuredGraph graph, SchedulingStrategy strategy, boolean immutable) { + runWithoutContextOptimizations(graph, strategy, ControlFlowGraph.computeForSchedule(graph), immutable); + } + + public static void runWithoutContextOptimizations(StructuredGraph graph, SchedulingStrategy strategy, ControlFlowGraph cfg, boolean immutable) { + Instance inst = new Instance(cfg, false); + inst.run(graph, strategy, immutable); + } + + public static void run(StructuredGraph graph, SchedulingStrategy strategy, ControlFlowGraph cfg, CoreProviders context, boolean immutable) { + Instance inst = new Instance(cfg, context.getLowerer().supportsImplicitNullChecks()); + inst.run(graph, strategy, immutable); } public static class Instance { @@ -173,19 +195,19 @@ public static class Instance { protected ControlFlowGraph cfg; protected BlockMap> blockToNodesMap; protected NodeMap nodeToBlockMap; + protected boolean supportsImplicitNullChecks; - public Instance() { - this(null); + public Instance(boolean supportsImplicitNullChecks) { + this(null, supportsImplicitNullChecks); } - public Instance(ControlFlowGraph cfg) { + public Instance(ControlFlowGraph cfg, boolean supportsImplicitNullChecks) { this.cfg = cfg; + this.supportsImplicitNullChecks = supportsImplicitNullChecks; } @SuppressWarnings("try") public void run(StructuredGraph graph, SchedulingStrategy selectedStrategy, boolean immutableGraph) { - // assert GraphOrder.assertNonCyclicGraph(graph); - if (this.cfg == null) { this.cfg = ControlFlowGraph.compute(graph, true, true, true, false); } @@ -206,7 +228,7 @@ public void run(StructuredGraph graph, SchedulingStrategy selectedStrategy, bool } BlockMap> watchListMap = calcLatestBlocks(selectedStrategy, currentNodeMap, earliestBlockToNodesMap, visited, latestBlockToNodesMap, immutableGraph); - sortNodesLatestWithinBlock(cfg, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited); + sortNodesLatestWithinBlock(cfg, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited, supportsImplicitNullChecks); assert verifySchedule(cfg, latestBlockToNodesMap, currentNodeMap); assert (!Assertions.detailedAssertionsEnabled(graph.getOptions())) || @@ -409,14 +431,14 @@ private static void fillKillSet(LocationSet killed, List subList) { } private static void sortNodesLatestWithinBlock(ControlFlowGraph cfg, BlockMap> earliestBlockToNodesMap, BlockMap> latestBlockToNodesMap, NodeMap currentNodeMap, - BlockMap> watchListMap, NodeBitMap visited) { + BlockMap> watchListMap, NodeBitMap visited, boolean supportsImplicitNullChecks) { for (Block b : cfg.getBlocks()) { - sortNodesLatestWithinBlock(b, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited); + sortNodesLatestWithinBlock(b, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited, supportsImplicitNullChecks); } } private static void sortNodesLatestWithinBlock(Block b, BlockMap> earliestBlockToNodesMap, BlockMap> latestBlockToNodesMap, NodeMap nodeMap, - BlockMap> watchListMap, NodeBitMap unprocessed) { + BlockMap> watchListMap, NodeBitMap unprocessed, boolean supportsImplicitNullChecks) { List earliestSorting = earliestBlockToNodesMap.get(b); ArrayList result = new ArrayList<>(earliestSorting.size()); ArrayList watchList = null; @@ -452,7 +474,7 @@ private static void sortNodesLatestWithinBlock(Block b, BlockMap> ear sortIntoList(n, b, result, nodeMap, unprocessed, null); } else if (nodeMap.get(n) == b && n instanceof FloatingReadNode) { FloatingReadNode floatingReadNode = (FloatingReadNode) n; - if (isImplicitNullOpportunity(floatingReadNode, b)) { + if (isImplicitNullOpportunity(floatingReadNode, b, supportsImplicitNullChecks)) { // Schedule at the beginning of the block. sortIntoList(floatingReadNode, b, result, nodeMap, unprocessed, null); } else { @@ -596,7 +618,7 @@ protected void calcLatestBlock(Block earliestBlock, SchedulingStrategy strategy, } } - if (latestBlock != earliestBlock && strategy.considerImplicitNullChecks() && isImplicitNullOpportunity(currentNode, earliestBlock) && + if (latestBlock != earliestBlock && strategy.considerImplicitNullChecks() && isImplicitNullOpportunity(currentNode, earliestBlock, supportsImplicitNullChecks) && earliestBlock.getRelativeFrequency() < latestBlock.getRelativeFrequency() * IMPLICIT_NULL_CHECK_OPPORTUNITY_PROBABILITY_FACTOR) { latestBlock = earliestBlock; } @@ -604,7 +626,10 @@ protected void calcLatestBlock(Block earliestBlock, SchedulingStrategy strategy, selectLatestBlock(currentNode, earliestBlock, latestBlock, currentNodeMap, watchListMap, constrainingLocation, latestBlockToNodesMap); } - protected static boolean isImplicitNullOpportunity(Node currentNode, Block block) { + protected static boolean isImplicitNullOpportunity(Node currentNode, Block block, boolean supportsImplicitNullChecks) { + if (!supportsImplicitNullChecks) { + return false; + } if (currentNode instanceof FloatingReadNode) { FloatingReadNode floatingReadNode = (FloatingReadNode) currentNode; Node pred = block.getBeginNode().predecessor(); diff --git a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java index 2eebfa16ecac..d9ca05e27db8 100644 --- a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java +++ b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java @@ -159,9 +159,8 @@ private static void visitForward(ArrayList nodes, NodeBitMap visited, Node public static boolean assertSchedulableGraph(final StructuredGraph graph) { assert graph.getGuardsStage() != GuardsStage.AFTER_FSA : "Cannot use the BlockIteratorClosure after FrameState Assignment, HIR Loop Data Structures are no longer valid."; try (DebugContext.Scope s = graph.getDebug().scope("AssertSchedulableGraph")) { - final SchedulePhase schedulePhase = new SchedulePhase(getSchedulingPolicy(graph), true); + SchedulePhase.runWithoutContextOptimizations(graph, getSchedulingPolicy(graph), true); final EconomicMap loopEntryStates = EconomicMap.create(Equivalence.IDENTITY); - schedulePhase.apply(graph, false); final ScheduleResult schedule = graph.getLastSchedule(); BlockIteratorClosure closure = new BlockIteratorClosure() { diff --git a/compiler/src/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java b/compiler/src/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java index 343a6463af3c..736889cc0b52 100644 --- a/compiler/src/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java +++ b/compiler/src/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java @@ -58,12 +58,15 @@ import org.graalvm.compiler.nodes.ControlSinkNode; import org.graalvm.compiler.nodes.ControlSplitNode; import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.PhiNode; import org.graalvm.compiler.nodes.ProxyNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.VirtualState; import org.graalvm.compiler.nodes.cfg.Block; import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; +import org.graalvm.compiler.nodes.memory.MultiMemoryKill; +import org.graalvm.compiler.nodes.memory.SingleMemoryKill; import org.graalvm.compiler.nodes.util.JavaConstantFormattable; import org.graalvm.graphio.GraphBlocks; import org.graalvm.graphio.GraphElements; @@ -246,6 +249,15 @@ public void nodeProperties(GraphInfo info, Node node, Map props) } } + if (info.cfg != null) { + if (node instanceof LoopBeginNode) { + // check if cfg is up to date + if (info.cfg.getLocalLoopFrequencyData().containsKey((LoopBeginNode) node)) { + props.put("localLoopFrequency", info.cfg.localLoopFrequency((LoopBeginNode) node)); + } + } + } + if (node instanceof ControlSinkNode) { props.put("category", "controlSink"); } else if (node instanceof ControlSplitNode) { @@ -271,6 +283,14 @@ public void nodeProperties(GraphInfo info, Node node, Map props) } props.put("category", "floating"); } + + if (node instanceof SingleMemoryKill) { + props.put("killedLocationIdentity", ((SingleMemoryKill) node).getKilledLocationIdentity()); + } + if (node instanceof MultiMemoryKill) { + props.put("killedLocationIdentities", ((MultiMemoryKill) node).getKilledLocationIdentities()); + } + if (getSnippetReflectionProvider() != null) { for (Map.Entry prop : props.entrySet()) { if (prop.getValue() instanceof JavaConstantFormattable) { diff --git a/compiler/src/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java b/compiler/src/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java index 622ea233d6e6..b690d993d9bb 100644 --- a/compiler/src/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java +++ b/compiler/src/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java @@ -270,14 +270,17 @@ private static DisassemblerProvider selectDisassemblerProvider(OptionValues opti String arch = Services.getSavedProperties().get("os.arch"); final boolean isAArch64 = arch.equals("aarch64"); for (DisassemblerProvider d : GraalServices.load(DisassemblerProvider.class)) { - String name = d.getName(); - if (isAArch64 && name.equals("objdump") && d.isAvailable(options)) { - return d; - } else if (name.equals("hcf")) { - if (!isAArch64) { + if (d.isAvailable(options)) { + String name = d.getName(); + if (isAArch64 && name.equals("objdump")) { + // Prefer objdump disassembler over others return d; + } else if (name.equals("hcf")) { + if (!isAArch64) { + return d; + } + selected = d; } - selected = d; } } if (selected == null) { diff --git a/compiler/src/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraalDebugHandlersFactory.java b/compiler/src/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraalDebugHandlersFactory.java index 1a1978fa47e2..018d1f2695c4 100644 --- a/compiler/src/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraalDebugHandlersFactory.java +++ b/compiler/src/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraalDebugHandlersFactory.java @@ -101,8 +101,7 @@ static ScheduleResult tryGetSchedule(DebugContext debug, StructuredGraph graph) // Also provide a schedule when an error occurs if (DebugOptions.PrintGraphWithSchedule.getValue(graph.getOptions()) || debug.contextLookup(Throwable.class) != null) { try (DebugCloseable noIntercept = debug.disableIntercept()) { - SchedulePhase schedule = new SchedulePhase(graph.getOptions()); - schedule.apply(graph); + SchedulePhase.runWithoutContextOptimizations(graph); scheduleResult = graph.getLastSchedule(); } catch (Throwable t) { } diff --git a/compiler/src/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java b/compiler/src/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java index e4ae066bc3ed..16b790efd6ec 100644 --- a/compiler/src/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java +++ b/compiler/src/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java @@ -249,8 +249,7 @@ static StructuredGraph.ScheduleResult getScheduleOrNull(Graph graph) { if (scheduleResult == null) { DebugContext debug = graph.getDebug(); try (Scope scope = debug.disable()) { - SchedulePhase schedule = new SchedulePhase(graph.getOptions()); - schedule.apply(sgraph); + SchedulePhase.runWithoutContextOptimizations(sgraph); scheduleResult = sgraph.getLastSchedule(); } catch (Throwable t) { } diff --git a/compiler/src/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java b/compiler/src/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java index d2f281b42711..484cbc84bd4d 100644 --- a/compiler/src/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java +++ b/compiler/src/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java @@ -24,6 +24,7 @@ */ package org.graalvm.compiler.replacements.aarch64; +import static org.graalvm.compiler.replacements.ArrayIndexOf.STUB_INDEX_OF_1_CHAR_COMPACT; import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.COS; import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.EXP; import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG; @@ -42,6 +43,8 @@ import org.graalvm.compiler.nodes.calc.LeftShiftNode; import org.graalvm.compiler.nodes.calc.MaxNode; import org.graalvm.compiler.nodes.calc.MinNode; +import org.graalvm.compiler.nodes.calc.NarrowNode; +import org.graalvm.compiler.nodes.calc.ZeroExtendNode; import org.graalvm.compiler.nodes.extended.JavaReadNode; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; @@ -53,6 +56,7 @@ import org.graalvm.compiler.nodes.memory.address.IndexAddressNode; import org.graalvm.compiler.nodes.spi.Replacements; import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.replacements.ArrayIndexOfDispatchNode; import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins.StringLatin1IndexOfCharPlugin; import org.graalvm.compiler.replacements.StringLatin1Substitutions; import org.graalvm.compiler.replacements.StringUTF16Substitutions; @@ -313,7 +317,15 @@ private static void registerStringUTF16Plugins(InvocationPlugins plugins, Replac r.register2("compareTo", byte[].class, byte[].class, new ArrayCompareToPlugin(JavaKind.Char, JavaKind.Char)); r.register2("compareToLatin1", byte[].class, byte[].class, new ArrayCompareToPlugin(JavaKind.Char, JavaKind.Byte, true)); r.registerMethodSubstitution(StringUTF16Substitutions.class, "indexOfUnsafe", byte[].class, int.class, byte[].class, int.class, int.class); - r.registerMethodSubstitution(StringUTF16Substitutions.class, "indexOfCharUnsafe", byte[].class, int.class, int.class, int.class); + r.register4("indexOfCharUnsafe", byte[].class, int.class, int.class, int.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value, ValueNode ch, ValueNode fromIndex, ValueNode max) { + ZeroExtendNode toChar = b.add(new ZeroExtendNode(b.add(new NarrowNode(ch, JavaKind.Char.getBitCount())), JavaKind.Int.getBitCount())); + b.addPush(JavaKind.Int, new ArrayIndexOfDispatchNode(STUB_INDEX_OF_1_CHAR_COMPACT, JavaKind.Byte, JavaKind.Char, false, value, max, fromIndex, + toChar)); + return true; + } + }); Registration r2 = new Registration(plugins, StringUTF16Substitutions.class, replacements); r2.register2("getChar", byte[].class, int.class, new InvocationPlugin() { @Override diff --git a/compiler/src/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64IntegerArithmeticSnippets.java b/compiler/src/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64IntegerArithmeticSnippets.java index c8b115a9abf0..2a395da9119c 100644 --- a/compiler/src/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64IntegerArithmeticSnippets.java +++ b/compiler/src/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64IntegerArithmeticSnippets.java @@ -36,6 +36,7 @@ import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.DeoptimizeNode; +import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; @@ -45,6 +46,7 @@ import org.graalvm.compiler.nodes.calc.UnsignedDivNode; import org.graalvm.compiler.nodes.calc.UnsignedRemNode; import org.graalvm.compiler.nodes.extended.BranchProbabilityNode; +import org.graalvm.compiler.nodes.extended.GuardingNode; import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.options.OptionValues; @@ -61,7 +63,7 @@ /** * Division in AArch64 ISA does not generate a trap when dividing by zero, but instead sets the - * result to 0. These snippets throw an ArithmethicException if the denominator is 0 and otherwise + * result to 0. These snippets throw an ArithmeticException if the denominator is 0 and otherwise * forward to the LIRGenerator. */ public class AArch64IntegerArithmeticSnippets extends AbstractTemplates implements Snippets { @@ -236,6 +238,13 @@ protected SafeSignedDivNode(ValueNode x, ValueNode y) { super(TYPE, x, y, null); } + @Override + protected SignedDivNode createWithInputs(ValueNode forX, ValueNode forY, GuardingNode forZeroCheck, FrameState forStateBefore) { + assert forZeroCheck == null; + // note that stateBefore is irrelevant, as this "safe" variant will not deoptimize + return new SafeSignedDivNode(forX, forY); + } + @Override public void generate(NodeLIRBuilderTool gen) { // override to ensure we always pass a null frame state @@ -252,6 +261,12 @@ protected SafeSignedRemNode(ValueNode x, ValueNode y) { super(TYPE, x, y, null); } + @Override + protected SignedRemNode createWithInputs(ValueNode forX, ValueNode forY, GuardingNode forZeroCheck) { + assert forZeroCheck == null; + return new SafeSignedRemNode(forX, forY); + } + @Override public void generate(NodeLIRBuilderTool gen) { // override to ensure we always pass a null frame state diff --git a/compiler/src/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java b/compiler/src/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java index ddeacaf576ec..1e6d1665a159 100644 --- a/compiler/src/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java +++ b/compiler/src/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java @@ -24,6 +24,7 @@ */ package org.graalvm.compiler.replacements.amd64; +import static org.graalvm.compiler.replacements.ArrayIndexOf.STUB_INDEX_OF_1_CHAR_COMPACT; import static org.graalvm.compiler.replacements.StandardGraphBuilderPlugins.STRING_VALUE_FIELD; import static org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation.POW; import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.COS; @@ -44,6 +45,8 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.CopySignNode; import org.graalvm.compiler.nodes.calc.LeftShiftNode; +import org.graalvm.compiler.nodes.calc.NarrowNode; +import org.graalvm.compiler.nodes.calc.ZeroExtendNode; import org.graalvm.compiler.nodes.extended.JavaReadNode; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; @@ -56,6 +59,7 @@ import org.graalvm.compiler.nodes.memory.address.IndexAddressNode; import org.graalvm.compiler.nodes.spi.Replacements; import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.replacements.ArrayIndexOfDispatchNode; import org.graalvm.compiler.replacements.InvocationPluginHelper; import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins; import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins.StringLatin1IndexOfCharPlugin; @@ -66,6 +70,8 @@ import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode; import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation; import org.graalvm.compiler.replacements.nodes.BitCountNode; +import org.graalvm.compiler.replacements.nodes.BitScanForwardNode; +import org.graalvm.compiler.replacements.nodes.BitScanReverseNode; import org.graalvm.compiler.replacements.nodes.FusedMultiplyAddNode; import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode; import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation; @@ -90,8 +96,8 @@ public static void register(Plugins plugins, Replacements replacements, AMD64 ar @Override public void run() { registerThreadPlugins(invocationPlugins, arch); - registerIntegerLongPlugins(invocationPlugins, AMD64IntegerSubstitutions.class, JavaKind.Int, arch, replacements); - registerIntegerLongPlugins(invocationPlugins, AMD64LongSubstitutions.class, JavaKind.Long, arch, replacements); + registerIntegerLongPlugins(invocationPlugins, JavaKind.Int, arch, replacements); + registerIntegerLongPlugins(invocationPlugins, JavaKind.Long, arch, replacements); if (GraalOptions.EmitStringSubstitutions.getValue(options)) { if (JavaVersionUtil.JAVA_SPEC <= 8) { registerStringPlugins(invocationPlugins, replacements); @@ -121,12 +127,42 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec } } - private static void registerIntegerLongPlugins(InvocationPlugins plugins, Class substituteDeclaringClass, JavaKind kind, AMD64 arch, Replacements replacements) { + private static void registerIntegerLongPlugins(InvocationPlugins plugins, JavaKind kind, AMD64 arch, Replacements replacements) { Class declaringClass = kind.toBoxedJavaClass(); Class type = kind.toJavaClass(); Registration r = new Registration(plugins, declaringClass, replacements); - r.registerMethodSubstitution(substituteDeclaringClass, "numberOfLeadingZeros", type); - r.registerMethodSubstitution(substituteDeclaringClass, "numberOfTrailingZeros", type); + r.register1("numberOfLeadingZeros", type, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { + if (arch.getFeatures().contains(AMD64.CPUFeature.LZCNT) && arch.getFlags().contains(AMD64.Flag.UseCountLeadingZerosInstruction)) { + b.addPush(JavaKind.Int, new AMD64CountLeadingZerosNode(arg)); + } else { + try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) { + // if (arg == 0) return kind.getBitCount(); + // return new kind.getBitCount() - 1 - BitScanReverseNode(arg); + helper.emitReturnIf(arg, Condition.EQ, ConstantNode.forIntegerKind(kind, 0), ConstantNode.forInt(kind.getBitCount()), GraalDirectives.UNLIKELY_PROBABILITY); + helper.emitFinalReturn(JavaKind.Int, helper.sub(ConstantNode.forInt(kind.getBitCount() - 1), new BitScanReverseNode(arg))); + } + } + return true; + } + }); + r.register1("numberOfTrailingZeros", type, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { + if (arch.getFeatures().contains(AMD64.CPUFeature.BMI1) && arch.getFlags().contains(AMD64.Flag.UseCountTrailingZerosInstruction)) { + b.addPush(JavaKind.Int, new AMD64CountTrailingZerosNode(arg)); + } else { + try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) { + // if (arg == 0) return kind.getBitCount(); + // return new BitScanForwardNode(arg); + helper.emitReturnIf(arg, Condition.EQ, ConstantNode.forIntegerKind(kind, 0), ConstantNode.forInt(kind.getBitCount()), GraalDirectives.UNLIKELY_PROBABILITY); + helper.emitFinalReturn(JavaKind.Int, b.add(new BitScanForwardNode(arg))); + } + } + return true; + } + }); r.registerConditional1(arch.getFeatures().contains(AMD64.CPUFeature.POPCNT), "bitCount", type, new InvocationPlugin() { @@ -465,7 +501,15 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec r.registerMethodSubstitution(StringUTF16Substitutions.class, "indexOfUnsafe", byte[].class, int.class, byte[].class, int.class, int.class); r.registerMethodSubstitution(StringUTF16Substitutions.class, "indexOfLatin1Unsafe", byte[].class, int.class, byte[].class, int.class, int.class); - r.registerMethodSubstitution(StringUTF16Substitutions.class, "indexOfCharUnsafe", byte[].class, int.class, int.class, int.class); + r.register4("indexOfCharUnsafe", byte[].class, int.class, int.class, int.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value, ValueNode ch, ValueNode fromIndex, ValueNode max) { + ZeroExtendNode toChar = b.add(new ZeroExtendNode(b.add(new NarrowNode(ch, JavaKind.Char.getBitCount())), JavaKind.Int.getBitCount())); + b.addPush(JavaKind.Int, new ArrayIndexOfDispatchNode(STUB_INDEX_OF_1_CHAR_COMPACT, JavaKind.Byte, JavaKind.Char, false, value, max, fromIndex, + toChar)); + return true; + } + }); Registration r2 = new Registration(plugins, StringUTF16Substitutions.class, replacements); r2.register2("getChar", byte[].class, int.class, new InvocationPlugin() { @Override diff --git a/compiler/src/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64IntegerSubstitutions.java b/compiler/src/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64IntegerSubstitutions.java deleted file mode 100644 index 6318e7494adc..000000000000 --- a/compiler/src/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64IntegerSubstitutions.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.replacements.amd64; - -import static org.graalvm.compiler.replacements.NodeIntrinsificationProvider.INJECTED_TARGET; - -import org.graalvm.compiler.api.replacements.ClassSubstitution; -import org.graalvm.compiler.api.replacements.Fold; -import org.graalvm.compiler.api.replacements.MethodSubstitution; -import org.graalvm.compiler.core.common.SuppressFBWarnings; -import org.graalvm.compiler.replacements.nodes.BitScanForwardNode; -import org.graalvm.compiler.replacements.nodes.BitScanReverseNode; - -import jdk.vm.ci.amd64.AMD64; -import jdk.vm.ci.code.TargetDescription; - -@ClassSubstitution(Integer.class) -public class AMD64IntegerSubstitutions { - - @Fold - static boolean lzcnt(@Fold.InjectedParameter TargetDescription target) { - AMD64 arch = (AMD64) target.arch; - return arch.getFeatures().contains(AMD64.CPUFeature.LZCNT) && arch.getFlags().contains(AMD64.Flag.UseCountLeadingZerosInstruction); - } - - @Fold - static boolean tzcnt(@Fold.InjectedParameter TargetDescription target) { - AMD64 arch = (AMD64) target.arch; - return arch.getFeatures().contains(AMD64.CPUFeature.BMI1) && arch.getFlags().contains(AMD64.Flag.UseCountTrailingZerosInstruction); - } - - @MethodSubstitution - @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF_NONVIRTUAL", justification = "foldable method parameters are injected") - public static int numberOfLeadingZeros(int i) { - if (lzcnt(INJECTED_TARGET)) { - return AMD64CountLeadingZerosNode.countLeadingZeros(i); - } - if (i == 0) { - return 32; - } - return 31 - BitScanReverseNode.unsafeScan(i); - } - - @MethodSubstitution - @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF_NONVIRTUAL", justification = "foldable method parameters are injected") - public static int numberOfTrailingZeros(int i) { - if (tzcnt(INJECTED_TARGET)) { - return AMD64CountTrailingZerosNode.countTrailingZeros(i); - } - if (i == 0) { - return 32; - } - return BitScanForwardNode.unsafeScan(i); - } -} diff --git a/compiler/src/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64LongSubstitutions.java b/compiler/src/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64LongSubstitutions.java deleted file mode 100644 index a1d5126138b9..000000000000 --- a/compiler/src/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64LongSubstitutions.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.replacements.amd64; - -// JaCoCo Exclude - -import static org.graalvm.compiler.replacements.NodeIntrinsificationProvider.INJECTED_TARGET; -import static org.graalvm.compiler.replacements.amd64.AMD64IntegerSubstitutions.lzcnt; -import static org.graalvm.compiler.replacements.amd64.AMD64IntegerSubstitutions.tzcnt; - -import org.graalvm.compiler.api.replacements.ClassSubstitution; -import org.graalvm.compiler.api.replacements.MethodSubstitution; -import org.graalvm.compiler.core.common.SuppressFBWarnings; -import org.graalvm.compiler.replacements.nodes.BitScanForwardNode; -import org.graalvm.compiler.replacements.nodes.BitScanReverseNode; - -@ClassSubstitution(Long.class) -public class AMD64LongSubstitutions { - - @MethodSubstitution - @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF_NONVIRTUAL", justification = "foldable method parameters are injected") - public static int numberOfLeadingZeros(long i) { - if (lzcnt(INJECTED_TARGET)) { - return AMD64CountLeadingZerosNode.countLeadingZeros(i); - } - if (i == 0) { - return 64; - } - return 63 - BitScanReverseNode.unsafeScan(i); - } - - @MethodSubstitution - @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF_NONVIRTUAL", justification = "foldable method parameters are injected") - public static int numberOfTrailingZeros(long i) { - if (tzcnt(INJECTED_TARGET)) { - return AMD64CountTrailingZerosNode.countTrailingZeros(i); - } - - if (i == 0) { - return 64; - } - return BitScanForwardNode.unsafeScan(i); - } -} diff --git a/compiler/src/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedFoldPlugin.java b/compiler/src/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedFoldPlugin.java index 1a3c1f8e21c8..595574be3f41 100644 --- a/compiler/src/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedFoldPlugin.java +++ b/compiler/src/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedFoldPlugin.java @@ -74,7 +74,7 @@ protected void createExecute(AbstractProcessor processor, PrintWriter out, Injec List params = intrinsicMethod.getParameters(); out.printf(" if (b.shouldDeferPlugin(this)) {\n"); - out.printf(" b.replacePlugin(this, targetMethod, args, %s.FUNCTION);\n", getReplacementName()); + out.printf(" b.replacePlugin%s(this, targetMethod, args, %s.FUNCTION);\n", getReplacementFunctionSuffix(processor), getReplacementName()); out.printf(" return true;\n"); out.printf(" }\n"); diff --git a/compiler/src/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedNodeIntrinsicPlugin.java b/compiler/src/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedNodeIntrinsicPlugin.java index 8d1690f72393..bb43edba67d1 100644 --- a/compiler/src/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedNodeIntrinsicPlugin.java +++ b/compiler/src/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedNodeIntrinsicPlugin.java @@ -186,7 +186,7 @@ protected void factoryCall(AbstractProcessor processor, PrintWriter out, Injecte out.printf(" }\n"); if (needsReplacement(processor) && !inReplacement) { out.printf(" if (b.canDeferPlugin(this)) {\n"); - out.printf(" b.replacePlugin(this, targetMethod, args, %s.FUNCTION);\n", getReplacementName()); + out.printf(" b.replacePlugin%s(this, targetMethod, args, %s.FUNCTION);\n", getReplacementFunctionSuffix(processor), getReplacementName()); out.printf(" return true;\n"); out.printf(" }\n"); out.printf(" throw GraalError.shouldNotReachHere(\"Can't inline plugin \" + b.getClass().toString());\n"); @@ -206,7 +206,19 @@ protected void verifyConstantArgument(PrintWriter out, String argName, TypeMirro @Override protected void createOtherClasses(AbstractProcessor processor, PrintWriter out) { if (needsReplacement(processor)) { - super.createOtherClasses(processor, out); + if (isWithExceptionReplacement(processor)) { + /* + * We need a WithExceptionNode replacement. + */ + String name = getReplacementName(); + out.printf("final class %s implements PluginReplacementWithExceptionNode.ReplacementWithExceptionFunction {\n", name); + out.printf(" static PluginReplacementWithExceptionNode.ReplacementWithExceptionFunction FUNCTION = new %s();\n", name); + InjectedDependencies deps = new InjectedDependencies(false, intrinsicMethod); + createHelpers(processor, out, deps); + out.printf("}\n"); + } else { + super.createOtherClasses(processor, out); + } } } diff --git a/compiler/src/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedPlugin.java b/compiler/src/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedPlugin.java index 0649c60ac9e1..b691ea63db8c 100644 --- a/compiler/src/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedPlugin.java +++ b/compiler/src/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedPlugin.java @@ -28,6 +28,7 @@ import java.util.Set; import java.util.function.Function; +import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; @@ -215,6 +216,12 @@ protected boolean needsReplacement(AbstractProcessor processor) { return true; } + protected boolean isWithExceptionReplacement(AbstractProcessor processor) { + Element nodeElement = intrinsicMethod.getEnclosingElement(); + TypeMirror withExceptionNodeType = processor.getType("org.graalvm.compiler.nodes.WithExceptionNode"); + return processor.env().getTypeUtils().isAssignable(nodeElement.asType(), withExceptionNodeType); + } + protected static String getReturnKind(ExecutableElement method) { switch (method.getReturnType().getKind()) { case BOOLEAN: @@ -304,7 +311,7 @@ protected String constantArgument(AbstractProcessor processor, out.printf(" } else {\n"); if (!isReplacement) { out.printf(" if (b.shouldDeferPlugin(this)) {\n"); - out.printf(" b.replacePlugin(this, targetMethod, args, %s.FUNCTION);\n", getReplacementName()); + out.printf(" b.replacePlugin%s(this, targetMethod, args, %s.FUNCTION);\n", getReplacementFunctionSuffix(processor), getReplacementName()); out.printf(" return true;\n"); out.printf(" }\n"); out.printf(" assert b.canDeferPlugin(this) : b.getClass().toString() + \" \" + %s;\n", argFormatter.apply(nodeIdx)); @@ -314,4 +321,8 @@ protected String constantArgument(AbstractProcessor processor, out.printf(" }\n"); return argName; } + + protected String getReplacementFunctionSuffix(AbstractProcessor processor) { + return isWithExceptionReplacement(processor) ? "WithException" : ""; + } } diff --git a/compiler/src/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/PluginGenerator.java b/compiler/src/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/PluginGenerator.java index d93dd69ef7d2..4cc14fa9327b 100644 --- a/compiler/src/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/PluginGenerator.java +++ b/compiler/src/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/PluginGenerator.java @@ -158,7 +158,11 @@ protected static void createImports(PrintWriter out, AbstractProcessor processor extra.add("org.graalvm.compiler.nodes.graphbuilderconf." + plugin.pluginSuperclass()); if (plugin.needsReplacement(processor)) { extra.add("org.graalvm.compiler.graph.NodeInputList"); - extra.add("org.graalvm.compiler.nodes.PluginReplacementNode"); + if (plugin.isWithExceptionReplacement(processor)) { + extra.add("org.graalvm.compiler.nodes.PluginReplacementWithExceptionNode"); + } else { + extra.add("org.graalvm.compiler.nodes.PluginReplacementNode"); + } } } Pattern packageClassBoundary = Pattern.compile("\\.([A-Z])"); diff --git a/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DerivedOopTest.java b/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DerivedOopTest.java index 6d317cecead1..5c8b5f56ffb6 100644 --- a/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DerivedOopTest.java +++ b/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DerivedOopTest.java @@ -37,7 +37,6 @@ import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; import org.graalvm.compiler.replacements.Snippets; -import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider; import org.graalvm.compiler.word.Word; import org.graalvm.compiler.word.WordCastNode; import org.junit.Assert; @@ -45,6 +44,7 @@ import org.junit.Test; import org.junit.rules.ExpectedException; +import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; /** @@ -253,13 +253,12 @@ public static Result fieldOffsetMergeSnippet03(Result objResult, Result a, Resul @Override protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) { Registration r = new Registration(invocationPlugins, DerivedOopTest.class); - ClassfileBytecodeProvider bytecodeProvider = getSystemClassLoaderBytecodeProvider(); - - ResolvedJavaMethod intrinsic = getResolvedJavaMethod("getRawPointerIntrinsic"); r.register1("getRawPointer", Object.class, new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { - return b.intrinsify(bytecodeProvider, targetMethod, intrinsic, receiver, new ValueNode[]{arg}); + WordCastNode objectToTracked = b.add(WordCastNode.objectToTrackedPointer(arg, getReplacements().getWordKind())); + b.addPush(JavaKind.Long, objectToTracked); + return true; } }); super.registerInvocationPlugins(invocationPlugins); diff --git a/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MonitorTest.java b/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MonitorTest.java index 0c44fa8bc3fd..8f6d0f9b28e1 100644 --- a/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MonitorTest.java +++ b/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MonitorTest.java @@ -212,9 +212,8 @@ public static String copyArr(char[] src, char[] dst, int n) { return new String(dst); } - @SuppressWarnings("synchronization") public static String lockBoxedLong(long value) { - Long lock = value; + Object lock = value; synchronized (lock) { return lock.toString(); } diff --git a/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTrackingTest.java b/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTrackingTest.java index e2ca0a9f1639..e4ecdb7f8b79 100644 --- a/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTrackingTest.java +++ b/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTrackingTest.java @@ -25,7 +25,6 @@ package org.graalvm.compiler.replacements.test; import org.graalvm.compiler.api.directives.GraalDirectives; -import org.graalvm.compiler.bytecode.BytecodeProvider; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; @@ -35,9 +34,10 @@ import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; import org.graalvm.compiler.replacements.Snippets; -import org.graalvm.compiler.word.Word; +import org.graalvm.compiler.word.WordCastNode; import org.junit.Test; +import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; public class PointerTrackingTest extends ReplacementsTest implements Snippets { @@ -111,30 +111,24 @@ static long getUntrackedPointer(@SuppressWarnings("unused") Object obj) { throw GraalError.shouldNotReachHere("should be intrinsified"); } - static long getTrackedPointerIntrinsic(Object obj) { - return Word.objectToTrackedPointer(obj).rawValue(); - } - - static long getUntrackedPointerIntrinsic(Object obj) { - return Word.objectToUntrackedPointer(obj).rawValue(); - } - - private void register(Registration r, String fnName) { - ResolvedJavaMethod intrinsic = getResolvedJavaMethod(fnName + "Intrinsic"); - BytecodeProvider bytecodeProvider = getSystemClassLoaderBytecodeProvider(); - r.register1(fnName, Object.class, new InvocationPlugin() { + @Override + protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) { + Registration r = new Registration(invocationPlugins, PointerTrackingTest.class); + r.register1("getTrackedPointer", Object.class, new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { - return b.intrinsify(bytecodeProvider, targetMethod, intrinsic, receiver, new ValueNode[]{arg}); + WordCastNode objectToTracked = b.add(WordCastNode.objectToTrackedPointer(arg, getReplacements().getWordKind())); + b.addPush(JavaKind.Long, objectToTracked); + return true; + } + }); + r.register1("getUntrackedPointer", Object.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { + WordCastNode objectToTracked = b.add(WordCastNode.objectToUntrackedPointer(arg, getReplacements().getWordKind())); + b.addPush(JavaKind.Long, objectToTracked); + return true; } }); - } - - @Override - protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) { - Registration r = new Registration(invocationPlugins, PointerTrackingTest.class); - - register(r, "getTrackedPointer"); - register(r, "getUntrackedPointer"); } } diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/AllocationSnippets.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/AllocationSnippets.java index f1fbb9982810..98c8cdc2fb90 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/AllocationSnippets.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/AllocationSnippets.java @@ -50,7 +50,7 @@ public abstract class AllocationSnippets implements Snippets { protected Object allocateInstanceImpl(Word hub, Word prototypeMarkWord, UnsignedWord size, - boolean fillContents, + FillContent fillContents, boolean emitMemoryBarrier, boolean constantSize, AllocationProfilingData profilingData) { @@ -76,7 +76,7 @@ protected Object allocateArrayImpl(Word hub, int length, int arrayBaseOffset, int log2ElementSize, - boolean fillContents, + FillContent fillContents, int fillStartOffset, boolean emitMemoryBarrier, boolean maybeUnroll, @@ -267,15 +267,15 @@ protected Object formatObject(Word hub, Word prototypeMarkWord, UnsignedWord size, Word memory, - boolean fillContents, + FillContent fillContents, boolean emitMemoryBarrier, boolean constantSize, AllocationSnippetCounters snippetCounters) { initializeObjectHeader(memory, hub, prototypeMarkWord, false); int headerSize = instanceHeaderSize(); - if (fillContents) { + if (fillContents == FillContent.WITH_ZEROES) { zeroMemory(memory, headerSize, size, constantSize, false, false, false, snippetCounters); - } else if (REPLACEMENTS_ASSERTIONS_ENABLED) { + } else if (REPLACEMENTS_ASSERTIONS_ENABLED && fillContents == FillContent.WITH_GARBAGE_IF_ASSERTIONS_ENABLED) { fillWithGarbage(memory, headerSize, size, constantSize, false, false, snippetCounters); } if (emitMemoryBarrier) { @@ -292,7 +292,7 @@ protected Object formatArray(Word hub, UnsignedWord allocationSize, int length, Word memory, - boolean fillContents, + FillContent fillContents, int fillStartOffset, boolean emitMemoryBarrier, boolean maybeUnroll, @@ -303,9 +303,9 @@ protected Object formatArray(Word hub, // Store hub last as the concurrent garbage collectors assume length is valid if hub field // is not null. initializeObjectHeader(memory, hub, prototypeMarkWord, true); - if (fillContents) { + if (fillContents == FillContent.WITH_ZEROES) { zeroMemory(memory, fillStartOffset, allocationSize, false, maybeUnroll, supportsBulkZeroing, supportsOptimizedFilling, snippetCounters); - } else if (REPLACEMENTS_ASSERTIONS_ENABLED) { + } else if (REPLACEMENTS_ASSERTIONS_ENABLED && fillContents == FillContent.WITH_GARBAGE_IF_ASSERTIONS_ENABLED) { fillWithGarbage(memory, fillStartOffset, allocationSize, false, maybeUnroll, supportsOptimizedFilling, snippetCounters); } if (emitMemoryBarrier) { @@ -374,6 +374,19 @@ protected Object callNewInstanceStub(Word hub, UnsignedWord size) { protected abstract int objectAlignment(); + public enum FillContent { + DO_NOT_FILL, + WITH_ZEROES, + WITH_GARBAGE_IF_ASSERTIONS_ENABLED; + + public static FillContent fromBoolean(boolean fillContents) { + if (fillContents) { + return WITH_ZEROES; + } + return WITH_GARBAGE_IF_ASSERTIONS_ENABLED; + } + } + public static class AllocationProfilingData { final AllocationSnippetCounters snippetCounters; diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java index 9d69d73b4fb1..4f6bca46b658 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java @@ -208,6 +208,11 @@ public void initialize(OptionValues options, Iterable fact providers.getReplacements().registerSnippetTemplateCache(new SnippetCounterNode.SnippetCounterSnippets.Templates(options, factories, providers, snippetReflection, target)); } + @Override + public boolean supportsImplicitNullChecks() { + return target.implicitNullCheckLimit > 0; + } + public final TargetDescription getTarget() { return target; } @@ -313,7 +318,7 @@ public void lower(Node n, LoweringTool tool) { private static void lowerComputeObjectAddressNode(ComputeObjectAddressNode n) { /* - * Lower the node into a ComputeObjectAddress node and an Add but ensure that it's below any + * Lower the node into a GetObjectAddressNode node and an Add but ensure that it's below any * potential safepoints and above it's uses. */ for (Node use : n.usages().snapshot()) { @@ -620,6 +625,18 @@ protected void lowerLoadHubOrNullNode(LoadHubOrNullNode loadHubOrNullNode, Lower if (graph.getGuardsStage().allowsFloatingGuards()) { return; } + ValueNode object = loadHubOrNullNode.getValue(); + if (object.isConstant() && !object.asJavaConstant().isNull()) { + /* + * Special case: insufficient canonicalization was run since the last lowering, if we + * are loading the hub from a constant we want to still fold it. + */ + ValueNode synonym = LoadHubNode.findSynonym(object, loadHubOrNullNode.stamp(NodeView.DEFAULT), tool.getMetaAccess(), tool.getConstantReflection()); + if (synonym != null) { + loadHubOrNullNode.replaceAtUsagesAndDelete(graph.maybeAddOrUnique(synonym)); + return; + } + } final FixedWithNextNode predecessor = tool.lastFixedNode(); final ValueNode value = loadHubOrNullNode.getValue(); AbstractPointerStamp stamp = (AbstractPointerStamp) value.stamp(NodeView.DEFAULT); diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntegerSubstitutions.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntegerSubstitutions.java deleted file mode 100644 index 3274061db711..000000000000 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntegerSubstitutions.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.replacements; - -import org.graalvm.compiler.api.replacements.ClassSubstitution; -import org.graalvm.compiler.api.replacements.MethodSubstitution; -import org.graalvm.compiler.replacements.nodes.BitScanForwardNode; -import org.graalvm.compiler.replacements.nodes.BitScanReverseNode; - -@ClassSubstitution(Integer.class) -public class IntegerSubstitutions { - - @MethodSubstitution - public static int numberOfLeadingZeros(int i) { - if (i == 0) { - return 32; - } - return 31 - BitScanReverseNode.unsafeScan(i); - } - - @MethodSubstitution - public static int numberOfTrailingZeros(int i) { - if (i == 0) { - return 32; - } - return BitScanForwardNode.unsafeScan(i); - } -} diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java index c3bf9559a205..a88f8654d9f5 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java @@ -41,6 +41,8 @@ import org.graalvm.compiler.nodes.BeginNode; import org.graalvm.compiler.nodes.CallTargetNode; import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; +import org.graalvm.compiler.nodes.DeoptimizeNode; +import org.graalvm.compiler.nodes.EndNode; import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.FrameState; @@ -59,12 +61,15 @@ import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver; +import org.graalvm.compiler.nodes.graphbuilderconf.MethodSubstitutionPlugin; import org.graalvm.compiler.nodes.java.ExceptionObjectNode; import org.graalvm.compiler.nodes.spi.CoreProviders; import org.graalvm.compiler.nodes.spi.CoreProvidersDelegate; import org.graalvm.compiler.options.OptionValues; import jdk.vm.ci.code.BailoutException; +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -84,6 +89,7 @@ public class IntrinsicGraphBuilder extends CoreProvidersDelegate implements Grap protected FixedWithNextNode lastInstr; protected ValueNode[] arguments; protected ValueNode returnValue; + private boolean parsingIntrinsic; private FrameState createStateAfterStartOfReplacementGraph(ResolvedJavaMethod original, GraphBuilderConfiguration graphBuilderConfig) { FrameStateBuilder startFrameState = new FrameStateBuilder(this, code, graph, graphBuilderConfig.retainLocalVariables()); @@ -278,7 +284,15 @@ public Bytecode getCode() { @Override public ResolvedJavaMethod getMethod() { - return method; + /* + * Invocation plugins expect to get the caller method that triggers the intrinsification. + * Since we are compiling the intrinsic on its own, we do not have any such caller method. + * + * In particular, returning `method` would be misleading because it is the method that is + * intrinsified, not the caller. The invocation plugin gets that method passed in as the + * `targetMethod` already. + */ + return null; } @Override @@ -303,7 +317,7 @@ public int getDepth() { @Override public boolean parsingIntrinsic() { - return true; + return parsingIntrinsic; } @Override @@ -322,7 +336,8 @@ public ValueNode get(boolean performNullCheck) { } @SuppressWarnings("try") - public StructuredGraph buildGraph(InvocationPlugin plugin) { + public final StructuredGraph buildGraph(InvocationPlugin plugin) { + parsingIntrinsic = plugin instanceof MethodSubstitutionPlugin; // The caller is expected to have filtered out decorator plugins since they cannot be // processed without special handling. assert !plugin.isDecorator() : plugin; @@ -345,10 +360,15 @@ public StructuredGraph buildGraph(InvocationPlugin plugin) { } @Override - public FrameState getIntrinsicReturnState(JavaKind returnKind, ValueNode retVal) { + public FrameState getInvocationPluginReturnState(JavaKind returnKind, ValueNode retVal) { return getGraph().add(new FrameState(AFTER_BCI)); } + @Override + public FrameState getInvocationPluginBeforeState() { + return getGraph().start().stateAfter(); + } + @Override public boolean canMergeIntrinsicReturns() { return true; @@ -364,6 +384,19 @@ public boolean intrinsify(ResolvedJavaMethod targetMethod, StructuredGraph subst return false; } + @Override + public boolean isParsingInvocationPlugin() { + return true; + } + + @Override + public Invoke invokeFallback(FixedWithNextNode predecessor, EndNode end) { + assert isParsingInvocationPlugin(); + DeoptimizeNode deopt = getGraph().add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint)); + predecessor.setNext(deopt); + return null; + } + @Override public String toString() { return String.format("%s:intrinsic", method.format("%H.%n(%p)")); diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InvocationPluginHelper.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InvocationPluginHelper.java index 8b59e56f0b0c..4827f1260f14 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InvocationPluginHelper.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InvocationPluginHelper.java @@ -24,10 +24,14 @@ */ package org.graalvm.compiler.replacements; +import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE; + import java.util.ArrayList; +import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.GraalError; @@ -35,13 +39,17 @@ import org.graalvm.compiler.nodes.BeginNode; import org.graalvm.compiler.nodes.ComputeObjectAddressNode; import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.DeoptimizeNode; import org.graalvm.compiler.nodes.EndNode; -import org.graalvm.compiler.nodes.FixedGuardNode; import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.Invoke; import org.graalvm.compiler.nodes.LogicNode; import org.graalvm.compiler.nodes.MergeNode; import org.graalvm.compiler.nodes.NodeView; +import org.graalvm.compiler.nodes.PiNode; import org.graalvm.compiler.nodes.ProfileData; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.ValuePhiNode; @@ -60,27 +68,28 @@ import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; import org.graalvm.compiler.nodes.java.ArrayLengthNode; import org.graalvm.compiler.nodes.java.LoadFieldNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; +import org.graalvm.compiler.nodes.type.StampTool; +import org.graalvm.compiler.word.Word; import jdk.vm.ci.code.CodeUtil; -import jdk.vm.ci.meta.DeoptimizationAction; -import jdk.vm.ci.meta.DeoptimizationReason; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; /** - * This is a helper class for writing moderately complex - * {@link org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin InvocationPlugins}. It's - * intentionally more limited than something like {@link GraphKit} because it's rarely useful to - * write explicit plugins for complex pieces of logic. They are better handled by writing a snippet - * for the complex logic and having an {@link InvocationPlugin} that performs any required null - * checks or range checks and then adds a node which is later lowered from the snippet. A major - * reason for this is that any complex control invariably has {@link MergeNode MergeNodes} which are - * required to have a valid {@link org.graalvm.compiler.nodes.FrameState} when they comes out of the - * parser. For intrinsics the only valid {@link org.graalvm.compiler.nodes.FrameState FrameStates} - * is the entry state and the state after then return and it can be hard to correctly assign states - * to the merges. There is also little benefit to introducing complex intrinsic graphs early because - * their are rarely amenable to high level optimizations. + * This is a helper class for writing moderately complex {@link InvocationPlugin InvocationPlugins}. + * It's intentionally more limited than something like {@link GraphKit} because it's rarely useful + * to write explicit plugins for complex pieces of logic. They are better handled by writing a + * snippet for the complex logic and having an {@link InvocationPlugin} that performs any required + * null checks or range checks and then adds a node which is later lowered by the snippet. A major + * reason for this is that any complex control invariably has {@link MergeNode}s which are required + * to have a valid {@link FrameState}s when they comes out of the parser. For intrinsics the only + * valid {@link FrameState}s is the entry state and the state after the return and it can be hard to + * correctly assign states to the merges. There is also little benefit to introducing complex + * intrinsic graphs early because they are rarely amenable to high level optimizations. * * The recommended usage pattern is to construct the helper instance in a try/resource block, which * performs some sanity checking when the block is exited. @@ -91,22 +100,22 @@ * * * The main idiom provided is {@link #emitReturnIf(LogicNode, boolean, ValueNode, double)} plus - * variants. It models a side exit from a main sequence of logic. - * {@link org.graalvm.compiler.nodes.FixedWithNextNode FixedWithNextNodes} are inserted in the main - * control flow and until the final return value is emitted with + * variants. It models a side exit from a main sequence of logic. {@link FixedWithNextNode}s are + * inserted in the main control flow and until the final return value is emitted with * {@link #emitFinalReturn(JavaKind, ValueNode)}. If only a single value is returned the normal * {@link GraphBuilderContext#addPush(JavaKind, ValueNode)} can be used instead. */ public class InvocationPluginHelper implements DebugCloseable { protected final GraphBuilderContext b; - protected final JavaKind wordKind; + private final JavaKind wordKind; private final JavaKind returnKind; private final ArrayList returns = new ArrayList<>(); private boolean emittedReturn; + private FixedWithNextNode fallbackEntry; public ValueNode arraylength(ValueNode receiverValue) { - // assert StampTool.isPointerAlwaysNull(receiverValue); - return b.add(new ArrayLengthNode(receiverValue)); + assert StampTool.isPointerNonNull(receiverValue); + return b.add(ArrayLengthNode.create(receiverValue, b.getConstantReflection())); } @Override @@ -116,6 +125,14 @@ public void close() { } } + public JavaKind getWordKind() { + return wordKind; + } + + public PiNode piCast(ValueNode value, GuardingNode nonnullGuard, Stamp stamp) { + return b.add(new PiNode(value, stamp, nonnullGuard.asNode())); + } + static class ReturnData { final EndNode end; final ValueNode returnValue; @@ -166,10 +183,13 @@ public ValueNode sub(ValueNode x, ValueNode y) { } public ValueNode length(ValueNode x) { + assert StampTool.typeOrNull(x) != null && StampTool.typeOrNull(x).isArray() : x.stamp(NodeView.DEFAULT); return b.add(new ArrayLengthNode(x)); } public ValueNode arrayElementPointer(ValueNode array, JavaKind kind, ValueNode index) { + assert StampTool.typeOrNull(array) != null && StampTool.typeOrNull(array).isArray() : array.stamp(NodeView.DEFAULT); + assert StampTool.typeOrNull(array).getComponentType().getJavaKind() == kind : array.stamp(NodeView.DEFAULT); int arrayBaseOffset = b.getMetaAccess().getArrayBaseOffset(kind); ValueNode offset = ConstantNode.forInt(arrayBaseOffset); if (index != null) { @@ -179,11 +199,32 @@ public ValueNode arrayElementPointer(ValueNode array, JavaKind kind, ValueNode i return b.add(new ComputeObjectAddressNode(array, asWord(offset))); } + /** + * Returns the address of the first element of an array. + */ + public ValueNode arrayStart(ValueNode array, JavaKind kind) { + return arrayElementPointer(array, kind, null); + } + + /** + * Shifts {@code index} by the proper amount based on the element kind. + */ public ValueNode scale(ValueNode index, JavaKind kind) { int arrayIndexShift = CodeUtil.log2(b.getMetaAccess().getArrayIndexScale(kind)); return shl(index, arrayIndexShift); } + /** + * Builds an {@link OffsetAddressNode} ensuring that the offset is also converted to a + * {@link Word}. + */ + public AddressNode makeOffsetAddress(ValueNode base, ValueNode offset) { + return b.add(new OffsetAddressNode(base, asWord(offset))); + } + + /** + * Ensures a primitive type is word sized. + */ public ValueNode asWord(ValueNode index) { assert index.getStackKind().isPrimitive(); if (index.getStackKind() != wordKind) { @@ -192,6 +233,10 @@ public ValueNode asWord(ValueNode index) { return index; } + public ValueNode asWord(long index) { + return ConstantNode.forIntegerKind(wordKind, index); + } + private LogicNode createCompare(ValueNode origX, ValueNode origY, Condition.CanonicalizedCondition canonicalizedCondition) { // Check whether the condition needs to mirror the operands. ValueNode x = origX; @@ -200,10 +245,10 @@ private LogicNode createCompare(ValueNode origX, ValueNode origY, Condition.Cano x = origY; y = origX; } - return createCompare(canonicalizedCondition.getCanonicalCondition(), x, y); + return createCompare(x, canonicalizedCondition.getCanonicalCondition(), y); } - public LogicNode createCompare(CanonicalCondition cond, ValueNode x, ValueNode y) { + public LogicNode createCompare(ValueNode x, CanonicalCondition cond, ValueNode y) { assert !x.getStackKind().isNumericFloat(); switch (cond) { case EQ: @@ -225,12 +270,34 @@ public ValueNode loadField(ValueNode value, ResolvedJavaField field) { b.getOptions(), b.getAssumptions(), value, field, false, false)); } - public void guard(ValueNode origX, Condition condition, ValueNode origY, DeoptimizationAction action, DeoptimizationReason deoptReason) { - Condition.CanonicalizedCondition canonicalizedCondition = condition.canonicalize(); - LogicNode compare = createCompare(origX, origY, canonicalizedCondition); - b.add(new FixedGuardNode(compare, deoptReason, action, !canonicalizedCondition.mustNegate())); + /** + * Finds a Java field by name. + * + * @throws GraalError if the field isn't found. + */ + public ResolvedJavaField getField(ResolvedJavaType type, String fieldName) { + for (ResolvedJavaField field : type.getInstanceFields(true)) { + if (field.getName().equals(fieldName)) { + return field; + } + } + throw new GraalError("missing field " + fieldName + " in type " + type); } + /** + * Gets the offset of a field. Normally InvocationPlugins are run in the target VM so nothing + * special needs to be done to handle these offsets but if a {@link Snippet} even triggers a + * plugin that uses a field offset them some extra machinery will be needed to delay the lookup. + */ + public ValueNode getFieldOffset(ResolvedJavaType type, String fieldName) { + GraalError.guarantee(!IS_BUILDING_NATIVE_IMAGE || !b.parsingIntrinsic(), "these values must be deferred in substitutions and snippets"); + return ConstantNode.forInt(getField(type, fieldName).getOffset()); + } + + /** + * Performs a range check for an intrinsic. This is a range check that represents a hard error + * in the intrinsic so it's permissible to throw an exception directly for this case. + */ public GuardingNode intrinsicRangeCheck(ValueNode x, Condition condition, ValueNode y) { Condition.CanonicalizedCondition canonicalizedCondition = condition.canonicalize(); LogicNode compare = createCompare(x, y, canonicalizedCondition); @@ -252,17 +319,17 @@ public AbstractBeginNode emitReturnIfNot(LogicNode condition, ValueNode returnVa } /** - * Build an {@link IfNode} that returns a value based on the condition and the negated flag. + * Builds an {@link IfNode} that returns a value based on the condition and the negated flag. * This can currently only be used for simple return values and doesn't allow {@link FixedNode * FixedNodes} to be part of the return path. All the return values are linked to a * {@link MergeNode} which terminates the graphs produced by the plugin. */ - public AbstractBeginNode emitReturnIf(LogicNode condition, boolean negated, ValueNode returnValue, double returnProbability) { + private AbstractBeginNode emitReturnIf(LogicNode condition, boolean negated, ValueNode returnValue, double returnProbability) { BeginNode trueSuccessor = b.getGraph().add(new BeginNode()); EndNode end = b.getGraph().add(new EndNode()); trueSuccessor.setNext(end); addReturnValue(end, returnKind, returnValue); - ProfileData.BranchProbabilityData probability = ProfileData.BranchProbabilityData.injected(returnProbability, true); + ProfileData.BranchProbabilityData probability = ProfileData.BranchProbabilityData.injected(returnProbability, negated); IfNode node = new IfNode(condition, negated ? null : trueSuccessor, negated ? trueSuccessor : null, probability); IfNode ifNode = b.append(node); BeginNode otherSuccessor = b.append(new BeginNode()); @@ -280,31 +347,34 @@ public void emitFinalReturn(JavaKind kind, ValueNode origReturnValue) { if (returnValue.isUnregistered()) { returnValue = b.append(returnValue); } - EndNode end = b.append(new EndNode()); - addReturnValue(end, kind, returnValue); - MergeNode returnMerge = b.append(new MergeNode()); - ValuePhiNode returnPhi = null; - if (returnKind != JavaKind.Void) { - returnPhi = b.add(new ValuePhiNode(StampFactory.forKind(returnKind), returnMerge)); - } - returnMerge.setStateAfter(b.getIntrinsicReturnState(kind, returnPhi)); - for (ReturnData r : returns) { - returnMerge.addForwardEnd(r.end); - if (returnPhi != null) { - returnPhi.addInput(r.returnValue); - } else { - assert r.returnValue == null; + if (returns.size() > 0) { + EndNode end = b.append(new EndNode()); + addReturnValue(end, kind, returnValue); + MergeNode returnMerge = b.append(new MergeNode()); + ValuePhiNode returnPhi = null; + if (returnKind != JavaKind.Void) { + returnPhi = b.add(new ValuePhiNode(StampFactory.forKind(returnKind), returnMerge)); + } + returnMerge.setStateAfter(b.getInvocationPluginReturnState(kind, returnPhi)); + for (ReturnData r : returns) { + returnMerge.addForwardEnd(r.end); + if (returnPhi != null) { + returnPhi.addInput(r.returnValue); + } else { + assert r.returnValue == null; + } } + returnValue = returnPhi.singleValueOrThis(); } - b.addPush(returnKind, returnPhi); + b.addPush(returnKind, returnValue); emittedReturn = true; } /** - * Connect an {@link EndNode} and return value into the final control flow merge. + * Connects an {@link EndNode} and return value into the final control flow merge. */ - private void addReturnValue(EndNode end, JavaKind kind, ValueNode returnValueInput) { + protected void addReturnValue(EndNode end, JavaKind kind, ValueNode returnValueInput) { assert b.canMergeIntrinsicReturns(); ValueNode returnValue = returnValueInput; if (returnValue.isUnregistered()) { @@ -312,7 +382,78 @@ private void addReturnValue(EndNode end, JavaKind kind, ValueNode returnValueInp returnValue = b.add(returnValue); } assert !returnValue.isUnregistered() : returnValue; - assert kind == returnKind; + assert kind == returnKind : "mismatch in return kind"; returns.add(new ReturnData(end, returnValue)); } + + /** + * Creates a branch to the fallback path, building a {@link MergeNode} if necessary. + */ + private BeginNode branchToFallback() { + if (fallbackEntry == null) { + BeginNode fallbackSuccessor = b.getGraph().add(new BeginNode()); + EndNode end = b.getGraph().add(new EndNode()); + Invoke invoke = b.invokeFallback(fallbackSuccessor, end); + if (invoke != null) { + fallbackEntry = fallbackSuccessor; + addReturnValue(end, returnKind, returnKind == JavaKind.Void ? null : invoke.asNode()); + } else { + assert end.predecessor() == null; + end.safeDelete(); + } + return fallbackSuccessor; + } + // Multiple paths lead to the fallback, so upgrade it to a MergeNode + if (!(fallbackEntry instanceof MergeNode)) { + assert fallbackEntry instanceof BeginNode; + BeginNode begin = (BeginNode) fallbackEntry; + FixedNode next = begin.next(); + EndNode end = b.getGraph().add(new EndNode()); + begin.setNext(end); + MergeNode merge = b.getGraph().add(new MergeNode()); + merge.addForwardEnd(end); + merge.setNext(next); + fallbackEntry = merge; + merge.setStateAfter(b.getInvocationPluginBeforeState()); + } + MergeNode fallbackMerge = (MergeNode) fallbackEntry; + BeginNode fallbackSuccessor = b.getGraph().add(new BeginNode()); + EndNode end = b.getGraph().add(new EndNode()); + fallbackSuccessor.setNext(end); + fallbackMerge.addForwardEnd(end); + return fallbackSuccessor; + } + + public GuardingNode doFallbackIf(ValueNode x, Condition condition, ValueNode y, double returnProbability) { + Condition.CanonicalizedCondition canonicalizedCondition = condition.canonicalize(); + LogicNode compare = createCompare(x, y, canonicalizedCondition); + return doFallbackIf(compare, canonicalizedCondition.mustNegate(), returnProbability); + } + + public GuardingNode doFallbackIfNot(LogicNode condition, double probability) { + return doFallbackIf(condition, true, probability); + } + + public GuardingNode doFallbackIf(LogicNode condition, double probability) { + return doFallbackIf(condition, false, probability); + } + + /** + * Fallback to the original implementation based on the {@code condition}. Depending on the + * environment the fallback may be done through a {@link DeoptimizeNode} or through a real + * {@link Invoke}. + */ + private GuardingNode doFallbackIf(LogicNode condition, boolean negated, double probability) { + BeginNode fallbackSuccessor = branchToFallback(); + ProfileData.BranchProbabilityData probabilityData = ProfileData.BranchProbabilityData.injected(probability, negated); + IfNode node = new IfNode(condition, negated ? null : fallbackSuccessor, negated ? fallbackSuccessor : null, probabilityData); + IfNode ifNode = b.append(node); + BeginNode fallThroughSuccessor = b.append(new BeginNode()); + if (negated) { + ifNode.setTrueSuccessor(fallThroughSuccessor); + } else { + ifNode.setFalseSuccessor(fallThroughSuccessor); + } + return fallThroughSuccessor; + } } diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/LongSubstitutions.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/LongSubstitutions.java deleted file mode 100644 index 2c9dc8777d42..000000000000 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/LongSubstitutions.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.replacements; - -import org.graalvm.compiler.api.replacements.ClassSubstitution; -import org.graalvm.compiler.api.replacements.MethodSubstitution; -import org.graalvm.compiler.replacements.nodes.BitScanForwardNode; -import org.graalvm.compiler.replacements.nodes.BitScanReverseNode; - -// JaCoCo Exclude - -@ClassSubstitution(Long.class) -public class LongSubstitutions { - - @MethodSubstitution - public static int numberOfLeadingZeros(long i) { - if (i == 0) { - return 64; - } - return 63 - BitScanReverseNode.unsafeScan(i); - } - - @MethodSubstitution - public static int numberOfTrailingZeros(long i) { - if (i == 0) { - return 64; - } - return BitScanForwardNode.unsafeScan(i); - } -} diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java index 697faafb0032..3ec9337c5810 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java @@ -84,7 +84,7 @@ import org.graalvm.compiler.nodes.MergeNode; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ParameterNode; -import org.graalvm.compiler.nodes.PluginReplacementNode; +import org.graalvm.compiler.nodes.PluginReplacementInterface; import org.graalvm.compiler.nodes.ReturnNode; import org.graalvm.compiler.nodes.SimplifyingGraphDecoder; import org.graalvm.compiler.nodes.StateSplit; @@ -120,6 +120,7 @@ import org.graalvm.compiler.nodes.java.NewMultiArrayNode; import org.graalvm.compiler.nodes.java.StoreFieldNode; import org.graalvm.compiler.nodes.java.StoreIndexedNode; +import org.graalvm.compiler.nodes.memory.MemoryKill; import org.graalvm.compiler.nodes.spi.Canonicalizable; import org.graalvm.compiler.nodes.spi.CoreProviders; import org.graalvm.compiler.nodes.spi.CoreProvidersDelegate; @@ -349,6 +350,11 @@ public boolean needsExplicitException() { return needsExplicitException; } + @Override + public boolean isParsingInvocationPlugin() { + return false; + } + /** * {@link Fold} and {@link NodeIntrinsic} can be deferred during parsing/decoding. Only by * the end of {@linkplain SnippetTemplate#instantiate Snippet instantiation} do they need to @@ -443,6 +449,15 @@ public Bytecode getCode() { @Override public ResolvedJavaMethod getMethod() { + if (isParsingInvocationPlugin()) { + /* + * While processing an invocation plugin, it is required to return the method that + * calls the intrinsified method. But our methodScope object is for the callee, + * i.e., the intrinsified method itself, for various other reasons. So we need to + * compensate for that. + */ + return methodScope.caller.method; + } return methodScope.method; } @@ -483,16 +498,23 @@ protected class PEAppendGraphBuilderContext extends PENonAppendGraphBuilderConte protected boolean exceptionEdgeConsumed; protected final InvokeKind invokeKind; protected final JavaType invokeReturnType; + protected final boolean parsingInvocationPlugin; public PEAppendGraphBuilderContext(PEMethodScope inlineScope, FixedWithNextNode lastInstr) { - this(inlineScope, lastInstr, null, null); + this(inlineScope, lastInstr, null, null, false); } - public PEAppendGraphBuilderContext(PEMethodScope inlineScope, FixedWithNextNode lastInstr, InvokeKind invokeKind, JavaType invokeReturnType) { + public PEAppendGraphBuilderContext(PEMethodScope inlineScope, FixedWithNextNode lastInstr, InvokeKind invokeKind, JavaType invokeReturnType, boolean parsingInvocationPlugin) { super(inlineScope, inlineScope.invokeData != null ? inlineScope.invokeData.invoke : null); this.lastInstr = lastInstr; this.invokeKind = invokeKind; this.invokeReturnType = invokeReturnType; + this.parsingInvocationPlugin = parsingInvocationPlugin; + } + + @Override + public boolean isParsingInvocationPlugin() { + return parsingInvocationPlugin; } @Override @@ -600,7 +622,7 @@ public void handleReplacedInvoke(CallTargetNode callTarget, JavaKind resultType) appendInvoke(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData, callTarget); - lastInstr.setNext(invoke.asNode()); + lastInstr.setNext(invoke.asFixedNode()); if (invoke instanceof InvokeWithExceptionNode) { lastInstr = ((InvokeWithExceptionNode) invoke).next(); } else { @@ -633,10 +655,10 @@ public GraphBuilderContext getNonIntrinsicAncestor() { } protected class PEPluginGraphBuilderContext extends PENonAppendGraphBuilderContext { - protected FixedWithNextNode insertBefore; + protected final FixedNode insertBefore; protected ValueNode pushedNode; - public PEPluginGraphBuilderContext(PEMethodScope inlineScope, FixedWithNextNode insertBefore) { + public PEPluginGraphBuilderContext(PEMethodScope inlineScope, FixedNode insertBefore) { super(inlineScope, inlineScope.invokeData != null ? inlineScope.invokeData.invoke : null); this.insertBefore = insertBefore; } @@ -685,9 +707,22 @@ private void updateLastInstruction(T value) { if (value instanceof FixedWithNextNode) { FixedWithNextNode fixed = (FixedWithNextNode) value; graph.addBeforeFixed(insertBefore, fixed); + } else if (value instanceof WithExceptionNode) { + WithExceptionNode withExceptionNode = (WithExceptionNode) value; + GraalError.guarantee(insertBefore instanceof WithExceptionNode, "Cannot replace %s with %s which is a %s", insertBefore, value, WithExceptionNode.class.getSimpleName()); + WithExceptionNode replacee = (WithExceptionNode) insertBefore; + graph.replaceWithExceptionSplit(replacee, withExceptionNode); + AbstractBeginNode next = withExceptionNode.next(); + if (withExceptionNode instanceof MemoryKill) { + /* Insert the correct memory killing begin node at the next edge. */ + GraalError.guarantee(next instanceof BeginNode, "Not a BeginNode %s", next); + AbstractBeginNode beginNode = graph.add(withExceptionNode.createNextBegin()); + withExceptionNode.setNext(beginNode); + beginNode.setNext(next); + } } else if (value instanceof FixedNode) { // Block terminating fixed nodes shouldn't be inserted - throw GraalError.shouldNotReachHere(); + throw GraalError.shouldNotReachHere(String.format("value: %s, insertBefore: %s", value, insertBefore)); } } } @@ -822,11 +857,6 @@ private void recordGraphElements(EncodedGraph encodedGraph) { } else { assert inlinedAssumptions == null : String.format("cannot inline graph (%s) which makes assumptions into a graph (%s) that doesn't", encodedGraph, graph); } - if (encodedGraph.getFields() != null) { - for (ResolvedJavaField field : encodedGraph.getFields()) { - graph.recordField(field); - } - } if (encodedGraph.hasUnsafeAccess()) { graph.markUnsafeAccess(); } @@ -944,7 +974,7 @@ protected MethodCallTargetNode trySimplifyCallTarget(PEMethodScope methodScope, if (callTarget.invokeKind().isInterface()) { Invoke invoke = invokeData.invoke; ResolvedJavaType contextType = methodScope.method.getDeclaringClass(); - return MethodCallTargetNode.tryDevirtualizeInterfaceCall(callTarget.receiver(), callTarget.targetMethod(), null, graph.getAssumptions(), contextType, callTarget, invoke.asNode()); + return MethodCallTargetNode.tryDevirtualizeInterfaceCall(callTarget.receiver(), callTarget.targetMethod(), null, graph.getAssumptions(), contextType, callTarget, invoke.asFixedNode()); } return callTarget; } @@ -1038,7 +1068,7 @@ protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopS PEMethodScope inlineScope = createMethodScope(graph, methodScope, loopScope, null, targetMethod, invokeData, methodScope.inliningDepth + 1, arguments); JavaType returnType = targetMethod.getSignature().getReturnType(methodScope.method.getDeclaringClass()); - PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(inlineScope, invokePredecessor, callTarget.invokeKind(), returnType); + PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(inlineScope, invokePredecessor, callTarget.invokeKind(), returnType, true); InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(graphBuilderContext); if (invocationPlugin.execute(graphBuilderContext, targetMethod, invocationPluginReceiver.init(targetMethod, arguments), arguments)) { @@ -1063,7 +1093,7 @@ protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopS } else { /* Intrinsification failed, restore original state: invoke is in Graph. */ - invokePredecessor.setNext(invoke.asNode()); + invokePredecessor.setNext(invoke.asFixedNode()); return false; } } @@ -1132,7 +1162,7 @@ protected LoopScope doInline(PEMethodScope methodScope, LoopScope loopScope, Inv } Invoke invoke = invokeData.invoke; - FixedNode invokeNode = invoke.asNode(); + FixedNode invokeNode = invoke.asFixedNode(); FixedWithNextNode predecessor = (FixedWithNextNode) invokeNode.predecessor(); invokeData.invokePredecessor = predecessor; invokeNode.replaceAtPredecessor(null); @@ -1188,7 +1218,7 @@ protected void finishInlining(MethodScope is) { LoopScope loopScope = inlineScope.callerLoopScope; InvokeData invokeData = inlineScope.invokeData; Invoke invoke = invokeData.invoke; - FixedNode invokeNode = invoke.asNode(); + FixedNode invokeNode = invoke.asFixedNode(); ValueNode exceptionValue = null; int returnNodeCount = 0; @@ -1487,10 +1517,10 @@ protected Node canonicalizeFixedNode(MethodScope s, Node node) { } } } - if (node instanceof PluginReplacementNode) { - PluginReplacementNode pluginReplacementNode = (PluginReplacementNode) node; + if (node instanceof PluginReplacementInterface) { + PluginReplacementInterface pluginReplacementNode = (PluginReplacementInterface) node; PEPluginGraphBuilderContext graphBuilderContext = new PEPluginGraphBuilderContext(methodScope, - pluginReplacementNode); + pluginReplacementNode.asFixedNode()); boolean success = pluginReplacementNode.replace(graphBuilderContext, providers.getReplacements()); if (success) { replacedNode = graphBuilderContext.pushedNode; diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java index 7dd3066e6bcb..85372b2d8d8f 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java @@ -98,8 +98,10 @@ import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.IfNode; import org.graalvm.compiler.nodes.InliningLog; import org.graalvm.compiler.nodes.InvokeWithExceptionNode; +import org.graalvm.compiler.nodes.LogicConstantNode; import org.graalvm.compiler.nodes.LogicNode; import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.LoopExitNode; @@ -109,6 +111,7 @@ import org.graalvm.compiler.nodes.PhiNode; import org.graalvm.compiler.nodes.PiNode.Placeholder; import org.graalvm.compiler.nodes.PiNode.PlaceholderStamp; +import org.graalvm.compiler.nodes.ProfileData; import org.graalvm.compiler.nodes.ReturnNode; import org.graalvm.compiler.nodes.StartNode; import org.graalvm.compiler.nodes.StateSplit; @@ -139,6 +142,8 @@ import org.graalvm.compiler.nodes.memory.MultiMemoryKill; import org.graalvm.compiler.nodes.memory.SingleMemoryKill; import org.graalvm.compiler.nodes.spi.ArrayLengthProvider; +import org.graalvm.compiler.nodes.spi.Canonicalizable; +import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodes.spi.CoreProviders; import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.nodes.spi.MemoryEdgeProxy; @@ -172,7 +177,7 @@ import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode; import org.graalvm.compiler.replacements.nodes.FallbackInvokeWithExceptionNode; import org.graalvm.compiler.replacements.nodes.LoadSnippetVarargParameterNode; -import org.graalvm.compiler.replacements.nodes.MacroStateSplitWithExceptionNode; +import org.graalvm.compiler.replacements.nodes.MacroWithExceptionNode; import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; import org.graalvm.util.CollectionsUtil; import org.graalvm.word.LocationIdentity; @@ -879,12 +884,7 @@ protected SnippetTemplate(OptionValues options, DebugContext debug, final Provid fallbackInvoke = fallbackInvokes.get(0); } - CanonicalizerPhase canonicalizer; - if (GraalOptions.ImmutableCode.getValue(snippetCopy.getOptions())) { - canonicalizer = CanonicalizerPhase.createWithoutReadCanonicalization(); - } else { - canonicalizer = CanonicalizerPhase.create(); - } + CanonicalizerPhase canonicalizer = CanonicalizerPhase.create(); /*- * Mirror the behavior of normal compilations here (without aggressive optimizations @@ -972,16 +972,7 @@ protected SnippetTemplate(OptionValues options, DebugContext debug, final Provid ArrayList curDeoptNodes = new ArrayList<>(); ArrayList curPlaceholderStampedNodes = new ArrayList<>(); - boolean containsMerge = false; - boolean containsLoopExit = false; - for (Node node : snippetCopy.getNodes()) { - if (node instanceof AbstractMergeNode) { - containsMerge = true; - } - if (node instanceof LoopExitNode) { - containsLoopExit = true; - } if (node instanceof ValueNode) { ValueNode valueNode = (ValueNode) node; if (valueNode.stamp(NodeView.DEFAULT) == PlaceholderStamp.singleton()) { @@ -1057,10 +1048,34 @@ protected SnippetTemplate(OptionValues options, DebugContext debug, final Provid debug.dump(DebugContext.INFO_LEVEL, snippet, "SnippetTemplate after fixing memory anchoring"); List returnNodes = snippet.getNodes(ReturnNode.TYPE).snapshot(); if (returnNodes.isEmpty()) { - this.returnNode = null; + /* + * The snippet does not have a return node. That can cause issues for subsequent + * lowerings if the replacee gets killed, because killCFG might kill a MergeNode + * that is still referenced by the LoweringTool. To solve this, we create an + * artificial return node and insert it into a temporary branch right after the + * start node. That way, the next node of the replacee will be attached to the + * artificial branch and killing the replacee will not affect its successor. The + * branch will fold away after snippet instantiation during canonicalization, + * together with the original successor. + */ + this.returnNode = snippet.add(new ReturnNode(getDefaultReturnValue(snippet, replacee))); + // insert empty memory map + MemoryMapImpl mmap = new MemoryMapImpl(); + MemoryMapNode memoryMap = snippet.unique(new MemoryMapNode(mmap.getMap())); + returnNode.setMemoryMap(memoryMap); + // this is the condition that controls the lifetime of the branch + this.artificialReturnCondition = snippet.unique(new PlaceholderLogicNode()); + // insert the temporary branch + FixedWithNextNode insertAfter = snippet.start(); + FixedNode next = insertAfter.next(); + insertAfter.setNext(null); + IfNode branch = snippet.add(new IfNode(artificialReturnCondition, next, this.returnNode, ProfileData.BranchProbabilityData.unknown())); + insertAfter.setNext(branch); } else if (returnNodes.size() == 1) { + this.artificialReturnCondition = null; this.returnNode = returnNodes.get(0); } else { + this.artificialReturnCondition = null; AbstractMergeNode merge = snippet.add(new MergeNode()); List memMaps = new ArrayList<>(); for (ReturnNode retNode : returnNodes) { @@ -1069,7 +1084,6 @@ protected SnippetTemplate(OptionValues options, DebugContext debug, final Provid memMaps.add(memoryMapNode); } } - containsMerge = true; ValueNode returnValue = InliningUtil.mergeReturns(merge, returnNodes); this.returnNode = snippet.add(new ReturnNode(returnValue)); if (!memMaps.isEmpty()) { @@ -1088,7 +1102,7 @@ protected SnippetTemplate(OptionValues options, DebugContext debug, final Provid debug.dump(DebugContext.INFO_LEVEL, snippet, "After fixing returns"); canonicalizer.apply(snippet, providers); - boolean needsMergeStateMap = !guardsStage.areFrameStatesAtDeopts() && (containsMerge || containsLoopExit); + boolean needsMergeStateMap = !guardsStage.areFrameStatesAtDeopts(); if (needsMergeStateMap) { frameStateAssignment = new SnippetFrameStateAssignmentClosure(snippetCopy); @@ -1125,6 +1139,19 @@ protected SnippetTemplate(OptionValues options, DebugContext debug, final Provid } } + /** + * Gets a default return value that is compatible with {@code replacee}. + */ + private static ValueNode getDefaultReturnValue(StructuredGraph snippet, Node replacee) { + if (replacee instanceof ValueNode) { + JavaKind javaKind = ((ValueNode) replacee).stamp(NodeView.DEFAULT).getStackKind(); + if (javaKind != JavaKind.Void) { + return ConstantNode.defaultForKind(javaKind, snippet); + } + } + return null; + } + private static boolean verifyIntrinsicsProcessed(StructuredGraph snippetCopy) { if (IS_IN_NATIVE_IMAGE) { return true; @@ -1150,12 +1177,7 @@ public static void explodeLoops(final StructuredGraph snippetCopy, CoreProviders if (loopBegin != null) { LoopEx loop = providers.getLoopsDataProvider().getLoopsData(snippetCopy).loop(loopBegin); Mark mark = snippetCopy.getMark(); - CanonicalizerPhase canonicalizer = null; - if (GraalOptions.ImmutableCode.getValue(snippetCopy.getOptions())) { - canonicalizer = CanonicalizerPhase.createWithoutReadCanonicalization(); - } else { - canonicalizer = CanonicalizerPhase.create(); - } + CanonicalizerPhase canonicalizer = CanonicalizerPhase.create(); try { LoopTransformations.fullUnroll(loop, providers, canonicalizer); } catch (RetryableBailoutException e) { @@ -1244,6 +1266,14 @@ private static boolean checkNonNull(ResolvedJavaMethod method, String parameterN */ private final ReturnNode returnNode; + /** + * The condition that keeps an artificial return node alive or {@code null} if no such return + * node has been added. During {@link SnippetTemplate#instantiate}, + * {@link PlaceholderLogicNode#markForDeletion()} will be called which cause the branch with the + * artificial return to fold away. + */ + private final PlaceholderLogicNode artificialReturnCondition; + /** * The node that will be replaced with the exception handler of the replacee node, or null if * the snippet does not have an exception handler path. @@ -1506,6 +1536,7 @@ public Collection getLocations() { } private void rewireMemoryGraph(ValueNode replacee, UnmodifiableEconomicMap duplicates) { + verifyWithExceptionNode(replacee); if (replacee.graph().isAfterStage(StageFlag.FLOATING_READS)) { // rewire outgoing memory edges replaceMemoryUsages(replacee, new MemoryOutputMap(replacee, duplicates)); @@ -1538,6 +1569,25 @@ private void rewireMemoryGraph(ValueNode replacee, UnmodifiableEconomicMap instantiate(MetaAccessProvider metaAc */ @SuppressWarnings("try") public UnmodifiableEconomicMap instantiate(MetaAccessProvider metaAccess, FixedNode replacee, UsageReplacer replacer, Arguments args, boolean killReplacee) { + if (!(replacee instanceof ControlSinkNode)) { + /* + * For all use cases of this, the replacee is killed sooner ({@code killReplacee == + * true}) or later (by the caller of this method). However, we cannot do that if the + * snippet does not have a return node we because that means we kill the {@code + * replacee.next()} which might be connected to a merge whose next node has not yet been + * lowered [GR-33909]. + */ + GraalError.guarantee(this.returnNode != null, "Cannot kill %s because snippet %s does not have a return node", replacee, this); + } + DebugContext debug = replacee.getDebug(); assert assertSnippetKills(replacee); try (DebugCloseable a = args.info.instantiationTimer.start(debug)) { @@ -1667,8 +1728,8 @@ public UnmodifiableEconomicMap instantiate(MetaAccessProvider metaAc } } if (unwindPath != null) { - GraalError.guarantee(replacee.graph().isBeforeStage(StageFlag.FLOATING_READS), - "Using a snippet with an UnwindNode after floating reads would require support for the memory graph"); + GraalError.guarantee(replacee.graph().isBeforeStage(StageFlag.FLOATING_READS) || replacee instanceof WithExceptionNode, + "Using a snippet with an UnwindNode after floating reads would require support for the memory graph (unless the replacee has an exception edge)"); GraalError.guarantee(replacee instanceof WithExceptionNode, "Snippet has an UnwindNode, but replacee is not a node with an exception handler"); FixedWithNextNode unwindPathDuplicate = (FixedWithNextNode) duplicates.get(unwindPath); @@ -1686,9 +1747,7 @@ public UnmodifiableEconomicMap instantiate(MetaAccessProvider metaAc * because lowering should not remove edges from the original CFG. */ if (replacee instanceof WithExceptionNode) { - GraalError.guarantee(replacee.graph().isBeforeStage(StageFlag.FLOATING_READS), - "Using a snippet with an UnwindNode after floating reads would require support for the memory graph"); - GraalError.guarantee(originalWithExceptionNextNode != null, "Need to have next node to link placeholder to."); + GraalError.guarantee(originalWithExceptionNextNode != null, "Need to have next node to link placeholder to: %s", replacee); WithExceptionNode newExceptionNode = replacee.graph().add(new PlaceholderWithExceptionNode()); @@ -1707,11 +1766,15 @@ public UnmodifiableEconomicMap instantiate(MetaAccessProvider metaAc } } + if (artificialReturnCondition != null) { + ((PlaceholderLogicNode) duplicates.get(artificialReturnCondition)).markForDeletion(); + } + if (fallbackInvoke != null) { - GraalError.guarantee(replacee instanceof MacroStateSplitWithExceptionNode, "%s can only be used in snippets replacing %s", FallbackInvokeWithExceptionNode.class.getSimpleName(), - MacroStateSplitWithExceptionNode.class.getSimpleName()); + GraalError.guarantee(replacee instanceof MacroWithExceptionNode, "%s can only be used in snippets replacing %s", FallbackInvokeWithExceptionNode.class.getSimpleName(), + MacroWithExceptionNode.class.getSimpleName()); WithExceptionNode fallbackInvokeNode = (WithExceptionNode) duplicates.get(fallbackInvoke); - MacroStateSplitWithExceptionNode macroNode = (MacroStateSplitWithExceptionNode) replacee; + MacroWithExceptionNode macroNode = (MacroWithExceptionNode) replacee; // create fallback invoke InvokeWithExceptionNode invoke = macroNode.createInvoke(returnValue); // replace placeholder @@ -1905,50 +1968,6 @@ private boolean requiresFrameStateProcessingBeforeFSA(ValueNode replacee) { } private void rewireFrameStatesBeforeFSA(ValueNode replacee, UnmodifiableEconomicMap duplicates, FixedNode replaceeGraphCFGPredecessor) { - if (replacee instanceof StateSplit && ((StateSplit) replacee).hasSideEffect() && ((StateSplit) replacee).stateAfter() != null) { - /* - * We have a side-effecting node that is lowered to a snippet that also contains - * side-effecting nodes. Either of 2 cases applies: either there is a frame state merge - * assignment meaning there are merges in the snippet that require states, then those - * will be assigned based on a reverse post order iteration of the snippet examining - * effects and trying to find a proper state, or no merges are in the graph, i.e., there - * is no complex control flow so every side-effecting node in the snippet can have the - * state after of the original node with the correct values replaced (i.e. the replacee - * itself in the snippet) - */ - for (StateSplit sideEffectNode : sideEffectNodes) { - assert ((StateSplit) replacee).hasSideEffect(); - Node sideEffectDup = duplicates.get(sideEffectNode.asNode()); - assert sideEffectDup != null : sideEffectNode; - FrameState stateAfter = ((StateSplit) replacee).stateAfter(); - assert stateAfter != null : "Replacee " + replacee + " has no state after"; - - if (sideEffectDup instanceof DeoptBciSupplier) { - if (replacee instanceof DeoptBciSupplier) { - ((DeoptBciSupplier) sideEffectDup).setBci(((DeoptBciSupplier) replacee).bci()); - } - } - if (stateAfter.values().contains(replacee)) { - FrameState duplicated = stateAfter.duplicate(); - ValueNode valueInReplacement = (ValueNode) duplicates.get(returnNode.result()); - if (valueInReplacement instanceof ValuePhiNode) { - valueInReplacement = (ValueNode) sideEffectDup; - } - ValueNode replacement = valueInReplacement; - duplicated.applyToNonVirtual(new NodePositionClosure() { - @Override - public void apply(Node from, Position p) { - if (p.get(from) == replacee) { - p.set(from, replacement); - } - } - }); - ((StateSplit) sideEffectDup).setStateAfter(duplicated); - } else { - ((StateSplit) sideEffectDup).setStateAfter(((StateSplit) replacee).stateAfter()); - } - } - } if (frameStateAssignment != null) { assignNecessaryFrameStates(replacee, duplicates, replaceeGraphCFGPredecessor); } @@ -1958,7 +1977,7 @@ private void assignNecessaryFrameStates(ValueNode replacee, UnmodifiableEconomic FrameState stateAfter = null; if (replacee instanceof StateSplit && ((StateSplit) replacee).hasSideEffect()) { stateAfter = ((StateSplit) replacee).stateAfter(); - assert stateAfter != null : "Statesplit with side-effect needs a framestate " + replacee; + GraalError.guarantee(stateAfter != null, "Statesplit with side-effect %s needs a framestate", replacee); } else { /* * We dont have a state split as a replacee, thus we take the prev state as the state @@ -1970,22 +1989,17 @@ private void assignNecessaryFrameStates(ValueNode replacee, UnmodifiableEconomic MapCursor stateAssignments = assignedStateMappings.getEntries(); while (stateAssignments.advance()) { Node nodeRequiringState = stateAssignments.getKey(); + + if (nodeRequiringState instanceof DeoptBciSupplier) { + if (replacee instanceof DeoptBciSupplier) { + ((DeoptBciSupplier) duplicates.get(nodeRequiringState)).setBci(((DeoptBciSupplier) replacee).bci()); + } + } + NodeStateAssignment assignment = stateAssignments.getValue(); switch (assignment) { case AFTER_BCI: - FrameState newState = stateAfter.duplicate(); - if (stateAfter.values().contains(replacee)) { - ValueNode valueInReplacement = (ValueNode) duplicates.get(returnNode.result()); - newState.applyToNonVirtual(new NodePositionClosure() { - @Override - public void apply(Node from, Position p) { - if (p.get(from) == replacee) { - p.set(from, valueInReplacement); - } - } - }); - } - ((StateSplit) duplicates.get(nodeRequiringState)).setStateAfter(newState); + setReplaceeGraphStateAfter(nodeRequiringState, replacee, duplicates, stateAfter); break; case BEFORE_BCI: FrameState stateBeforeSnippet = findLastFrameState(replaceeGraphCFGPredecessor); @@ -2000,11 +2014,37 @@ public void apply(Node from, Position p) { default: throw GraalError.shouldNotReachHere("Unknown StateAssigment:" + assignment); } - replacee.graph().getDebug().dump(DebugContext.VERY_DETAILED_LEVEL, - replacee.graph(), "After duplicating after state for node %s in snippet", duplicates.get(nodeRequiringState)); + replacee.graph().getDebug().dump(DebugContext.VERY_DETAILED_LEVEL, replacee.graph(), "After duplicating after state for node %s in snippet", duplicates.get(nodeRequiringState)); } } + private void setReplaceeGraphStateAfter(Node nodeRequiringState, Node replacee, UnmodifiableEconomicMap duplicates, FrameState stateAfter) { + FrameState newState = stateAfter.duplicate(); + if (stateAfter.values().contains(replacee)) { + ValueNode valueInReplacement = (ValueNode) duplicates.get(returnNode.result()); + if (!(nodeRequiringState instanceof AbstractMergeNode || nodeRequiringState instanceof LoopExitNode)) { + // merges and loop exit cannot have "this node" on stack + if (valueInReplacement instanceof ValuePhiNode) { + Node sideEffectDup = duplicates.get(nodeRequiringState); + valueInReplacement = (ValueNode) sideEffectDup; + } + } + propagateValInState(newState, replacee, valueInReplacement); + } + ((StateSplit) duplicates.get(nodeRequiringState)).setStateAfter(newState); + } + + private static void propagateValInState(FrameState newState, Node replacee, Node replacement) { + newState.applyToNonVirtual(new NodePositionClosure() { + @Override + public void apply(Node from, Position p) { + if (p.get(from) == replacee) { + p.set(from, replacement); + } + } + }); + } + private void rewireFrameStatesAfterFSA(ValueNode replacee, UnmodifiableEconomicMap duplicates) { DeoptimizingNode replaceeDeopt = (DeoptimizingNode) replacee; FrameState stateBefore = null; @@ -2161,7 +2201,7 @@ public void setMayRemoveLocation(boolean mayRemoveLocation) { * CFG edges for select snippet lowerings. */ @NodeInfo(size = NodeSize.SIZE_0, cycles = NodeCycles.CYCLES_0, cyclesRationale = "This node is immediately removed on next simplification pass") -final class PlaceholderWithExceptionNode extends WithExceptionNode implements Simplifiable { +final class PlaceholderWithExceptionNode extends WithExceptionNode implements Simplifiable, SingleMemoryKill { static final NodeClass TYPE = NodeClass.create(PlaceholderWithExceptionNode.class); protected PlaceholderWithExceptionNode() { @@ -2175,4 +2215,32 @@ public void simplify(SimplifierTool tool) { } graph().removeSplit(this, next()); } + + @Override + public LocationIdentity getKilledLocationIdentity() { + return LocationIdentity.any(); + } +} + +@NodeInfo(size = NodeSize.SIZE_0, cycles = NodeCycles.CYCLES_0, cyclesRationale = "This node is immediately removed on next simplification pass") +final class PlaceholderLogicNode extends LogicNode implements Canonicalizable { + static final NodeClass TYPE = NodeClass.create(PlaceholderLogicNode.class); + private boolean delete; + + protected PlaceholderLogicNode() { + super(TYPE); + delete = false; + } + + public void markForDeletion() { + delete = true; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (delete) { + return LogicConstantNode.tautology(); + } + return this; + } } diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java index 9637b67cdcb2..bdc1e4638c77 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java @@ -273,6 +273,11 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec if (JavaVersionUtil.JAVA_SPEC <= 8) { Registration sr = new Registration(plugins, StringSubstitutions.class); sr.register1("getValue", String.class, new InvocationPlugin() { + @Override + public boolean inlineOnly() { + return true; + } + @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { ResolvedJavaField field = b.getMetaAccess().lookupJavaField(STRING_VALUE_FIELD); @@ -308,6 +313,11 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec Registration sr = new Registration(plugins, JDK9StringSubstitutions.class); sr.register1("getValue", String.class, new InvocationPlugin() { + @Override + public boolean inlineOnly() { + return true; + } + @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { ResolvedJavaField field = b.getMetaAccess().lookupJavaField(STRING_VALUE_FIELD); @@ -318,6 +328,11 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec } }); sr.register1("getCoder", String.class, new InvocationPlugin() { + @Override + public boolean inlineOnly() { + return true; + } + @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { ResolvedJavaField field = b.getMetaAccess().lookupJavaField(STRING_CODER_FIELD); @@ -327,6 +342,11 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec } }); sr.register2("getByte", byte[].class, int.class, new InvocationPlugin() { + @Override + public boolean inlineOnly() { + return true; + } + @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2) { b.addPush(JavaKind.Byte, new JavaReadNode(JavaKind.Byte, @@ -375,59 +395,45 @@ static class StringEqualsInvocationPlugin implements InvocationPlugin { @SuppressWarnings("try") @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg2) { - // @formatter:off - // if (thisString == obj) { - // return true; - // } - // if (!(obj instanceof String)) { - // return false; - // } - // String thatString = (String) obj; - // if (getCoder(thisString) != getCoder(thatString)) { - // return false; - // } - // final byte[] array1 = getValue(thisString); - // final byte[] array2 = getValue(thatString); - // if (array1.length != array2.length) { - // return false; - // } - // if (array1.length == 0) { - // return true; - // } - // - // return ArrayEqualsNode.equals(array1, array2, GraalDirectives.isCompilationConstant(thatString) ? array2.length : array1.length); - // @formatter:on + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode other) { if (!b.canMergeIntrinsicReturns()) { return false; } try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) { - ResolvedJavaField valueField = b.getMetaAccess().lookupJavaField(STRING_VALUE_FIELD); + ConstantNode trueValue = ConstantNode.forBoolean(true); + ConstantNode falseValue = ConstantNode.forBoolean(false); - ValueNode arg1 = receiver.get(); - helper.emitReturnIf(b.add(new ObjectEqualsNode(arg1, arg2)), b.add(ConstantNode.forBoolean(true)), BranchProbabilityNode.SLOW_PATH_PROBABILITY); + // if (this == other) return true + ValueNode thisString = receiver.get(); + helper.emitReturnIf(b.add(new ObjectEqualsNode(thisString, other)), trueValue, BranchProbabilityNode.SLOW_PATH_PROBABILITY); + // if (!(other instanceof String)) return false TypeReference stringType = TypeReference.createTrusted(b.getAssumptions(), b.getMetaAccess().lookupJavaType(String.class)); - GuardingNode stringArg2Guard = helper.emitReturnIfNot(InstanceOfNode.create(stringType, arg2), b.add(ConstantNode.forBoolean(false)), + GuardingNode stringArg2Guard = helper.emitReturnIfNot(InstanceOfNode.create(stringType, other), b.add(falseValue), BranchProbabilityNode.SLOW_PATH_PROBABILITY); - Stamp stamp2 = StampFactory.objectNonNull(stringType); - ValueNode stringArg2 = b.add(new PiNode(arg2, stamp2, stringArg2Guard.asNode())); + Stamp stamp = StampFactory.objectNonNull(stringType); + ValueNode otherString = b.add(new PiNode(other, stamp, stringArg2Guard.asNode())); if (JavaVersionUtil.JAVA_SPEC > 8) { ResolvedJavaField coderField = b.getMetaAccess().lookupJavaField(STRING_CODER_FIELD); - ValueNode thisCoder = helper.loadField(arg1, coderField); - ValueNode thatCoder = helper.loadField(stringArg2, coderField); - helper.emitReturnIfNot(b.add(new IntegerEqualsNode(thisCoder, thatCoder)), b.add(ConstantNode.forBoolean(false)), BranchProbabilityNode.SLOW_PATH_PROBABILITY); + ValueNode thisCoder = helper.loadField(thisString, coderField); + ValueNode thatCoder = helper.loadField(otherString, coderField); + // if (thisString.coder != otherString.coder) return false + helper.emitReturnIfNot(b.add(new IntegerEqualsNode(thisCoder, thatCoder)), falseValue, BranchProbabilityNode.SLOW_PATH_PROBABILITY); } - ValueNode thisValue = b.nullCheckedValue(helper.loadField(stringArg2, valueField)); - ValueNode thatValue = b.nullCheckedValue(helper.loadField(arg1, valueField)); - - ValueNode thisLength = b.add(new ArrayLengthNode(thisValue)); - ValueNode thatLength = b.add(new ArrayLengthNode(thatValue)); - helper.emitReturnIfNot(IntegerEqualsNode.create(thisLength, thatLength, NodeView.DEFAULT), b.add(ConstantNode.forBoolean(false)), BranchProbabilityNode.SLOW_PATH_PROBABILITY); - helper.emitReturnIf(IntegerEqualsNode.create(thisLength, b.add(ConstantNode.forInt(0)), NodeView.DEFAULT), b.add(ConstantNode.forBoolean(true)), + ResolvedJavaField valueField = b.getMetaAccess().lookupJavaField(STRING_VALUE_FIELD); + ValueNode thisValue = b.nullCheckedValue(helper.loadField(otherString, valueField)); + ValueNode thatValue = b.nullCheckedValue(helper.loadField(thisString, valueField)); + + ValueNode thisLength = helper.arraylength(thisValue); + ValueNode thatLength = helper.arraylength(thatValue); + // if (thisString.value.length != otherString.value.length) return false + helper.emitReturnIfNot(IntegerEqualsNode.create(thisLength, thatLength, NodeView.DEFAULT), falseValue, BranchProbabilityNode.SLOW_PATH_PROBABILITY); + // if (length == 0) return true + helper.emitReturnIf(IntegerEqualsNode.create(thisLength, ConstantNode.forInt(0), NodeView.DEFAULT), trueValue, BranchProbabilityNode.SLOW_PATH_PROBABILITY); + // compare the array bodies helper.emitFinalReturn(JavaKind.Boolean, b.append(new ArrayEqualsNode(thisValue, thatValue, thisLength.isConstant() ? thisLength : thatLength, JavaVersionUtil.JAVA_SPEC > 8 ? JavaKind.Byte : JavaKind.Char))); } @@ -450,7 +456,9 @@ private static void registerArrayPlugins(InvocationPlugins plugins, Replacements r.register2("newInstance", Class.class, int.class, new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode componentType, ValueNode length) { - b.addPush(JavaKind.Object, new DynamicNewArrayNode(componentType, length, true)); + ValueNode componentTypeNonNull = b.nullCheckedValue(componentType); + ValueNode lengthPositive = b.maybeEmitExplicitNegativeArraySizeCheck(length); + b.addPush(JavaKind.Object, new DynamicNewArrayNode(componentTypeNonNull, lengthPositive, true)); return true; } }); @@ -988,7 +996,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec if (RegisterFinalizerNode.mayHaveFinalizer(object, b.getMetaAccess(), b.getAssumptions())) { RegisterFinalizerNode regFin = new RegisterFinalizerNode(object); b.add(regFin); - b.setStateAfter(regFin); + assert regFin.stateAfter() != null; } return true; } @@ -1893,35 +1901,23 @@ public static class StringLatin1IndexOfCharPlugin implements InvocationPlugin { @SuppressWarnings("try") @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value, ValueNode ch, ValueNode origFromIndex) { - // @formatter:off - // public static int indexOf(byte[] value, int ch, int origFromIndex) { - // int fromIndex = origFromIndex; - // if (injectBranchProbability(UNLIKELY_PROBABILITY, ch >>> 8 != 0)) { - // // search value must be a byte value - // return -1; - // } - // int length = value.length; - // if (injectBranchProbability(UNLIKELY_PROBABILITY, fromIndex < 0)) { - // fromIndex = 0; - // } else if (injectBranchProbability(UNLIKELY_PROBABILITY, fromIndex >= length)) { - // // Note: fromIndex might be near -1>>>1. - // return -1; - // } - // return ArrayIndexOf.indexOf1Byte(value, length, fromIndex, (byte) ch); - // } - // @formatter:on if (!b.canMergeIntrinsicReturns()) { return false; } try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) { ConstantNode zero = ConstantNode.forInt(0); + // if (ch >>> 8 != 0) return -1 helper.emitReturnIf(helper.ushr(ch, 8), Condition.NE, zero, ConstantNode.forInt(-1), GraalDirectives.UNLIKELY_PROBABILITY); ValueNode nonNullValue = b.nullCheckedValue(value); - ValueNode length = b.add(new ArrayLengthNode(nonNullValue)); + + // if (fromIndex >= value.length) return -1 + ValueNode length = helper.arraylength(nonNullValue); helper.emitReturnIf(origFromIndex, Condition.GE, length, ConstantNode.forInt(-1), GraalDirectives.UNLIKELY_PROBABILITY); - LogicNode condition = helper.createCompare(CanonicalCondition.LT, origFromIndex, zero); - ValueNode fromIndex = b.add(ConditionalNode.create(condition, zero, origFromIndex, NodeView.DEFAULT)); - helper.emitFinalReturn(JavaKind.Int, b.append(new ArrayIndexOfDispatchNode(STUB_INDEX_OF_1_BYTE, JavaKind.Byte, JavaKind.Byte, false, nonNullValue, length, fromIndex, ch))); + LogicNode condition = helper.createCompare(origFromIndex, CanonicalCondition.LT, zero); + // fromIndex = max(fromIndex, 0) + ValueNode fromIndex = ConditionalNode.create(condition, zero, origFromIndex, NodeView.DEFAULT); + helper.emitFinalReturn(JavaKind.Int, new ArrayIndexOfDispatchNode(STUB_INDEX_OF_1_BYTE, JavaKind.Byte, JavaKind.Byte, + false, nonNullValue, length, fromIndex, ch)); } return true; } diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StringUTF16Substitutions.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StringUTF16Substitutions.java index ae3d8589f741..0cb10b1a46a4 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StringUTF16Substitutions.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StringUTF16Substitutions.java @@ -73,11 +73,6 @@ private static Word charOffsetPointer(byte[] value, int offset) { */ private static native char getChar(byte[] value, int i); - @MethodSubstitution - public static int indexOfCharUnsafe(byte[] value, int ch, int fromIndex, int max) { - return ArrayIndexOf.indexOf1CharCompact(value, max, fromIndex, (char) ch); - } - @MethodSubstitution public static int indexOfUnsafe(byte[] source, int sourceCount, byte[] target, int targetCount, int fromIndex) { ReplacementsUtil.dynamicAssert(fromIndex >= 0, "StringUTF16.indexOfUnsafe invalid args: fromIndex negative"); diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopy.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopy.java deleted file mode 100644 index 8abf55d6c0a9..000000000000 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopy.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.replacements.arraycopy; - -import org.graalvm.compiler.debug.DebugContext; -import org.graalvm.compiler.graph.NodeInputList; -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.DeoptimizingNode; -import org.graalvm.compiler.nodes.FrameState; -import org.graalvm.compiler.nodes.NodeView; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.java.LoadIndexedNode; -import org.graalvm.compiler.nodes.memory.MemoryAccess; -import org.graalvm.compiler.nodes.memory.SingleMemoryKill; -import org.graalvm.compiler.nodes.spi.Lowerable; -import org.graalvm.compiler.nodes.spi.Virtualizable; -import org.graalvm.compiler.nodes.spi.VirtualizerTool; -import org.graalvm.compiler.nodes.type.StampTool; -import org.graalvm.compiler.nodes.virtual.VirtualArrayNode; -import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; - -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaType; - -/** - * Interface for all nodes that implement the {@link System#arraycopy} operation. Provides - * implementations for most operations concerning arraycopy. - */ -public interface ArrayCopy extends Virtualizable, SingleMemoryKill, MemoryAccess, Lowerable, DeoptimizingNode.DeoptDuring { - - int SRC_ARG = 0; - int SRC_POS_ARG = 1; - int DEST_ARG = 2; - int DEST_POS_ARG = 3; - int LENGTH_ARG = 4; - - NodeInputList args(); - - default ValueNode getSource() { - return args().get(SRC_ARG); - } - - default ValueNode getSourcePosition() { - return args().get(SRC_POS_ARG); - } - - default ValueNode getDestination() { - return args().get(DEST_ARG); - } - - default ValueNode getDestinationPosition() { - return args().get(DEST_POS_ARG); - } - - default ValueNode getLength() { - return args().get(LENGTH_ARG); - } - - int getBci(); - - JavaKind getElementKind(); - - default boolean checkBounds(int position, int length, VirtualObjectNode virtualObject) { - assert length >= 0; - return position >= 0 && position <= virtualObject.entryCount() - length; - } - - default boolean checkEntryTypes(int srcPos, int length, VirtualObjectNode src, ResolvedJavaType destComponentType, VirtualizerTool tool) { - if (destComponentType.getJavaKind() == JavaKind.Object && !destComponentType.isJavaLangObject()) { - for (int i = 0; i < length; i++) { - ValueNode entry = tool.getEntry(src, srcPos + i); - ResolvedJavaType type = StampTool.typeOrNull(entry); - if (type == null || !destComponentType.isAssignableFrom(type)) { - return false; - } - } - } - return true; - } - - /* - * Returns true if this copy doesn't require store checks. Trivially true for primitive arrays. - */ - default boolean isExact() { - ResolvedJavaType srcType = StampTool.typeOrNull(getSource().stamp(NodeView.DEFAULT)); - ResolvedJavaType destType = StampTool.typeOrNull(getDestination().stamp(NodeView.DEFAULT)); - if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) { - return false; - } - if ((srcType.getComponentType().getJavaKind().isPrimitive() && destType.getComponentType().equals(srcType.getComponentType())) || getSource() == getDestination()) { - return true; - } - - if (StampTool.isExactType(getDestination().stamp(NodeView.DEFAULT))) { - if (destType != null && destType.isAssignableFrom(srcType)) { - return true; - } - } - return false; - } - - @Override - default void virtualize(VirtualizerTool tool) { - ValueNode sourcePosition = tool.getAlias(getSourcePosition()); - ValueNode destinationPosition = tool.getAlias(getDestinationPosition()); - ValueNode replacedLength = tool.getAlias(getLength()); - - if (sourcePosition.isConstant() && destinationPosition.isConstant() && replacedLength.isConstant()) { - int srcPosInt = sourcePosition.asJavaConstant().asInt(); - int destPosInt = destinationPosition.asJavaConstant().asInt(); - int len = replacedLength.asJavaConstant().asInt(); - ValueNode destAlias = tool.getAlias(getDestination()); - - if (destAlias instanceof VirtualArrayNode) { - VirtualArrayNode destVirtual = (VirtualArrayNode) destAlias; - if (len < 0 || !checkBounds(destPosInt, len, destVirtual)) { - return; - } - ValueNode srcAlias = tool.getAlias(getSource()); - - if (srcAlias instanceof VirtualObjectNode) { - if (!(srcAlias instanceof VirtualArrayNode)) { - return; - } - VirtualArrayNode srcVirtual = (VirtualArrayNode) srcAlias; - if (destVirtual.componentType().getJavaKind() != srcVirtual.componentType().getJavaKind()) { - return; - } - if (!checkBounds(srcPosInt, len, srcVirtual)) { - return; - } - if (!checkEntryTypes(srcPosInt, len, srcVirtual, destVirtual.type().getComponentType(), tool)) { - return; - } - if (srcVirtual == destVirtual && srcPosInt < destPosInt) { - // must copy backwards to avoid losing elements - for (int i = len - 1; i >= 0; i--) { - tool.setVirtualEntry(destVirtual, destPosInt + i, tool.getEntry(srcVirtual, srcPosInt + i)); - } - } else { - for (int i = 0; i < len; i++) { - tool.setVirtualEntry(destVirtual, destPosInt + i, tool.getEntry(srcVirtual, srcPosInt + i)); - } - } - tool.delete(); - DebugContext debug = this.asNode().getDebug(); - if (debug.isLogEnabled()) { - debug.log("virtualized arraycopy(%s, %d, %s, %d, %d)", getSource(), srcPosInt, getDestination(), destPosInt, len); - } - } else { - ResolvedJavaType sourceType = StampTool.typeOrNull(srcAlias); - if (sourceType == null || !sourceType.isArray()) { - return; - } - ResolvedJavaType sourceComponentType = sourceType.getComponentType(); - ResolvedJavaType destComponentType = destVirtual.type().getComponentType(); - if (!sourceComponentType.equals(destComponentType)) { - return; - } - for (int i = 0; i < len; i++) { - LoadIndexedNode load = new LoadIndexedNode(this.asNode().graph().getAssumptions(), srcAlias, ConstantNode.forInt(i + srcPosInt, this.asNode().graph()), null, - destComponentType.getJavaKind()); - load.setNodeSourcePosition(this.asNode().getNodeSourcePosition()); - tool.addNode(load); - tool.setVirtualEntry(destVirtual, destPosInt + i, load); - } - tool.delete(); - } - } - } - } - - @Override - default boolean canDeoptimize() { - return true; - } - - @Override - default boolean hasSideEffect() { - return !getKilledLocationIdentity().isInit(); - } - - @Override - default void computeStateDuring(FrameState currentStateAfter) { - FrameState newStateDuring = currentStateAfter.duplicateModifiedDuringCall(getBci(), asNode().getStackKind()); - setStateDuring(newStateDuring); - } - - static JavaKind selectComponentKind(ArrayCopy arraycopy) { - ResolvedJavaType srcType = StampTool.typeOrNull(arraycopy.getSource().stamp(NodeView.DEFAULT)); - ResolvedJavaType destType = StampTool.typeOrNull(arraycopy.getDestination().stamp(NodeView.DEFAULT)); - - if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) { - return null; - } - if (!destType.getComponentType().isAssignableFrom(srcType.getComponentType())) { - return null; - } - if (!arraycopy.isExact()) { - return null; - } - return srcType.getComponentType().getJavaKind(); - } -} diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopyCallNode.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopyCallNode.java index efe3aa2b058a..3e9c19deb54d 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopyCallNode.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopyCallNode.java @@ -36,8 +36,6 @@ import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.Canonicalizable; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodeinfo.InputType; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ConstantNode; @@ -56,6 +54,8 @@ import org.graalvm.compiler.nodes.memory.MemoryKill; import org.graalvm.compiler.nodes.memory.SingleMemoryKill; import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; +import org.graalvm.compiler.nodes.spi.Canonicalizable; +import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.word.WordTypes; @@ -72,10 +72,6 @@ * based on the element type and memory properties. * * The target of the call is queried via {@link ArrayCopyLookup#lookupArraycopyDescriptor}. - * - * @see GenericArrayCopyCallNode A generic {@link System#arraycopy} stub call node. - * @see CheckcastArrayCopyCallNode A {@link System#arraycopy} stub call node that performs a fast - * check cast. */ @NodeInfo(allowedUsageTypes = {Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN) public final class ArrayCopyCallNode extends AbstractMemoryCheckpoint implements Lowerable, SingleMemoryKill, MemoryAccess, Canonicalizable { @@ -310,7 +306,7 @@ public void updateAlignedDisjoint(MetaAccessProvider metaAccess) { aligned = isHeapWordAligned(metaAccess, constantSrc, componentKind) && isHeapWordAligned(metaAccess, constantDst, componentKind); } if (constantSrc.asInt() >= constantDst.asInt()) { - // low to high copy so treat as disjoint + // low to high copy (copying forwards) so treat as disjoint disjoint = true; } } diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopyLookup.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopyLookup.java index abad4aa1ccd7..a70088d8c239 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopyLookup.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopyLookup.java @@ -25,40 +25,12 @@ package org.graalvm.compiler.replacements.arraycopy; import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; -import org.graalvm.compiler.core.common.spi.ForeignCallSignature; -import org.graalvm.compiler.word.Word; import org.graalvm.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; public interface ArrayCopyLookup { - /** - * Signature of an unsafe {@link System#arraycopy} stub. - * - * The signature is equivalent to {@link sun.misc.Unsafe#copyMemory(long, long, long)}. For the - * semantics refer to {@link sun.misc.Unsafe#copyMemory(Object, long, Object, long, long)}. - * - * @see sun.misc.Unsafe#copyMemory - */ - ForeignCallSignature UNSAFE_ARRAYCOPY = new ForeignCallSignature("unsafe_arraycopy", void.class, Word.class, Word.class, Word.class); - - /** - * Signature of a generic {@link System#arraycopy} stub. - * - * Instead of throwing an {@link ArrayStoreException}, the stub is expected to return the number - * of copied elements xor'd with {@code -1}. A return value of {@code 0} indicates that the - * operation was successful. - */ - ForeignCallSignature GENERIC_ARRAYCOPY = new ForeignCallSignature("generic_arraycopy", int.class, Word.class, int.class, Word.class, int.class, int.class); - - /** - * Looks up the call descriptor for a fast checkcast {@link System#arraycopy} stub. - * - * @see CheckcastArrayCopyCallNode - */ - ForeignCallDescriptor lookupCheckcastArraycopyDescriptor(boolean uninit); - /** * Looks up the call descriptor for a specialized {@link System#arraycopy} stub. * diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopyNode.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopyNode.java index 3515086552b5..a39208936b28 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopyNode.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopyNode.java @@ -57,20 +57,16 @@ public ArrayCopyNode(int bci, ValueNode src, ValueNode srcPos, ValueNode dst, Va super(TYPE, src, srcPos, dst, dstPos, length, null, bci); this.forceAnyLocation = forceAnyLocation; if (!forceAnyLocation) { - elementKind = ArrayCopy.selectComponentKind(this); + elementKind = selectComponentKind(this); } else { assert elementKind == null; } } - public ArrayCopyNode(ArrayCopy arraycopy) { - this(arraycopy.getBci(), arraycopy.getSource(), arraycopy.getSourcePosition(), arraycopy.getDestination(), arraycopy.getDestinationPosition(), arraycopy.getLength()); - } - @Override public LocationIdentity getKilledLocationIdentity() { if (!forceAnyLocation && elementKind == null) { - elementKind = ArrayCopy.selectComponentKind(this); + elementKind = selectComponentKind(this); } if (elementKind != null) { return NamedLocationIdentity.getArrayLocation(elementKind); diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopySnippets.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopySnippets.java index dea3f0910c52..f35b5f6765cb 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopySnippets.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopySnippets.java @@ -25,9 +25,7 @@ package org.graalvm.compiler.replacements.arraycopy; import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.DEOPT_PROBABILITY; -import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY; import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; import java.util.EnumMap; @@ -48,6 +46,8 @@ import org.graalvm.compiler.nodes.NamedLocationIdentity; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage; +import org.graalvm.compiler.nodes.UnreachableNode; import org.graalvm.compiler.nodes.java.ArrayLengthNode; import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.nodes.type.StampTool; @@ -76,6 +76,37 @@ /** * Snippets for lowering {@link System#arraycopy}. + * + *
    + *
  • {@link #arraycopyNativeExceptionSnippet}: this snippet is used when the array copy is known + * to throw an exception, either because at least one of the objects is not an array, or one is an + * object array and the other one a primitive array.
  • + *
  • {@link #arraycopyExactStubCallSnippet}: this snippet is used for array copies that do not + * require a store check. This is the case if the array copy is either + * {@linkplain BasicArrayCopyNode#isExact() exact}, i.e., we can prove that the source array type is + * assignable to the destination array type, or if one of the objects is a primitive array (and the + * other is unknown). In the latter case, it is sufficient to dynamically check that the array types + * are the same. No store check is needed.
  • + *
  • {@link #exactArraycopyWithExpandedLoopSnippet}: if we can do an + * {@linkplain #arraycopyExactStubCallSnippet array copy without store check}, it might be better to + * inline the copy loop to allow further compiler phases to optimize the code, instead of doing a + * stub call. This is only done if {@code mayExpandThisArraycopy} is {@code true}. Lowering is + * delayed until {@linkplain GuardsStage#FIXED_DEOPTS deopts are fixed} using + * {@link #delayedExactArraycopyWithExpandedLoopSnippet}.
  • + *
  • {@link #checkcastArraycopySnippet}: this snippet is used if at least one of the objects is an + * object array, but the compatibility of source and destination cannot be proven statically. We + * need to perform a store check on every element. Lowering is delayed {@link GuardsStage#AFTER_FSA + * after framestate assignment} via {@link #delayedCheckcastArraycopySnippet})
  • + *
  • {@link #genericArraycopySnippet}: this snippet is used if we have no information about the + * types of the objects. The snippet needs to perform all required type and store checks. Lowering + * is delayed {@link GuardsStage#AFTER_FSA after framestate assignment} via + * {@link #delayedGenericArraycopySnippet}.
  • + *
+ * + * See {@link Templates#lower(ArrayCopyNode, boolean, LoweringTool)} for the implementation details + * of the lowering strategies. + * + * @see Templates#lower(ArrayCopyNode, boolean, LoweringTool) */ public abstract class ArrayCopySnippets implements Snippets { @@ -91,7 +122,7 @@ private enum ArrayCopyTypeCheck { } /** Marker value for the {@link InjectedParameter} injected parameter. */ - static final MetaAccessProvider INJECTED_META_ACCESS = null; + protected static final MetaAccessProvider INJECTED_META_ACCESS = null; /** * Checks whether the hubs for the given objects are equal. The objects must be non-null. @@ -115,22 +146,21 @@ protected boolean useOriginalArraycopy() { } /** - * Snippet that performs an {@linkplain ArrayCopy#isExact() exact} array copy. Used when the - * array copy might be {@linkplain Templates#lower(ArrayCopyNode, boolean, LoweringTool) - * expanded}. - * - * @param workSnippet is always {@link #exactArraycopyWithSlowPathWork} which calls - * {@link #doExactArraycopyWithSlowPathWork} + * Snippet that performs an {@linkplain BasicArrayCopyNode#isExact() exact} array copy. Used + * when the array copy might be + * {@linkplain Templates#lower(ArrayCopyNode, boolean, LoweringTool) expanded}. Lowering is + * delayed using an {@link ArrayCopyWithDelayedLoweringNode} which will dispatch to + * {@link #exactArraycopyWithExpandedLoopSnippet}. * * @see Templates#lower(ArrayCopyNode, boolean, LoweringTool) - * @see #exactArraycopyWithSlowPathWork - * @see #doExactArraycopyWithSlowPathWork + * @see #exactArraycopyWithExpandedLoopSnippet + * @see #doExactArraycopyWithExpandedLoopSnippet */ @SuppressWarnings("unused") @Snippet - public void arraycopyExactSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter ArrayCopyTypeCheck arrayTypeCheck, - @ConstantParameter SnippetInfo workSnippet, @ConstantParameter JavaKind elementKind, @ConstantParameter LocationIdentity locationIdentity, - @ConstantParameter SnippetCounter elementKindCounter, @ConstantParameter SnippetCounter elementKindCopiedCounter, @ConstantParameter Counters counters) { + public void delayedExactArraycopyWithExpandedLoopSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter ArrayCopyTypeCheck arrayTypeCheck, + @ConstantParameter JavaKind elementKind, @ConstantParameter LocationIdentity locationIdentity, @ConstantParameter SnippetCounter elementKindCounter, + @ConstantParameter SnippetCounter elementKindCopiedCounter, @ConstantParameter Counters counters) { Object nonNullSrc = GraalDirectives.guardingNonNull(src); Object nonNullDest = GraalDirectives.guardingNonNull(dest); checkArrayTypes(nonNullSrc, nonNullDest, arrayTypeCheck); @@ -140,23 +170,18 @@ public void arraycopyExactSnippet(Object src, int srcPos, Object dest, int destP elementKindCounter.inc(); elementKindCopiedCounter.add(length); - ArrayCopyWithDelayedLoweringNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, workSnippet, elementKind); + // Don't lower until floating guards are fixed. + ArrayCopyWithDelayedLoweringNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, WorkSnippetID.exactArraycopyWithExpandedLoopSnippet, GuardsStage.FIXED_DEOPTS, elementKind); } /** - * Snippet that performs a stub call for an {@linkplain ArrayCopy#isExact() exact} array copy. - * - * @param workSnippet is always {@link #exactArraycopyWithSlowPathWork} which calls - * {@link #doExactArraycopyWithSlowPathWork} - * - * @see #exactArraycopyWithSlowPathWork - * @see #doExactArraycopyWithSlowPathWork + * Snippet that performs a stub call for an {@linkplain BasicArrayCopyNode#isExact() exact} + * array copy. */ - @SuppressWarnings("unused") @Snippet public void arraycopyExactStubCallSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter ArrayCopyTypeCheck arrayTypeCheck, - @ConstantParameter SnippetInfo workSnippet, @ConstantParameter JavaKind elementKind, @ConstantParameter LocationIdentity locationIdentity, - @ConstantParameter SnippetCounter elementKindCounter, @ConstantParameter SnippetCounter elementKindCopiedCounter, @ConstantParameter Counters counters) { + @ConstantParameter JavaKind elementKind, @ConstantParameter LocationIdentity locationIdentity, @ConstantParameter SnippetCounter elementKindCounter, + @ConstantParameter SnippetCounter elementKindCopiedCounter, @ConstantParameter Counters counters) { Object nonNullSrc = GraalDirectives.guardingNonNull(src); Object nonNullDest = GraalDirectives.guardingNonNull(dest); checkArrayTypes(nonNullSrc, nonNullDest, arrayTypeCheck); @@ -172,115 +197,112 @@ public void arraycopyExactStubCallSnippet(Object src, int srcPos, Object dest, i /** * Performs an array copy with a type check for every store. At least one of the involved * objects is known to be an object array. Lowering is delayed using an - * {@link ArrayCopyWithDelayedLoweringNode}. + * {@link ArrayCopyWithDelayedLoweringNode} which will dispatch to + * {@link #checkcastArraycopySnippet}. * - * @param workSnippet is always {@link #checkcastArraycopyWithSlowPathWork} which calls - * {@link #doCheckcastArraycopyWithSlowPathWork} + * @see #checkcastArraycopySnippet */ @Snippet - public void arraycopyCheckcastSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter ArrayCopyTypeCheck arrayTypeCheck, @ConstantParameter Counters counters, - @ConstantParameter SnippetInfo workSnippet, @ConstantParameter JavaKind elementKind) { + public void delayedCheckcastArraycopySnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter ArrayCopyTypeCheck arrayTypeCheck, + @ConstantParameter Counters counters, @ConstantParameter JavaKind elementKind) { Object nonNullSrc = GraalDirectives.guardingNonNull(src); Object nonNullDest = GraalDirectives.guardingNonNull(dest); checkArrayTypes(nonNullSrc, nonNullDest, arrayTypeCheck); checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters); incrementLengthCounter(length, counters); - ArrayCopyWithDelayedLoweringNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, workSnippet, elementKind); + // Don't lower until frame states are assigned to deoptimization points. + ArrayCopyWithDelayedLoweringNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, WorkSnippetID.checkcastArraycopySnippet, GuardsStage.AFTER_FSA, elementKind); } /** * Performs an array copy using a generic stub. Used when we do not know anything about the - * object types. Lowering is delayed using an {@link ArrayCopyWithDelayedLoweringNode}. + * object types. Lowering is delayed using an {@link ArrayCopyWithDelayedLoweringNode} which + * will dispatch to {@link #genericArraycopySnippet}. * - * @param workSnippet is always {@link #genericArraycopyWithSlowPathWork} + * @see #genericArraycopySnippet */ @Snippet - public void arraycopyGenericSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter ArrayCopyTypeCheck arrayTypeCheck, @ConstantParameter Counters counters, - @ConstantParameter SnippetInfo workSnippet, @ConstantParameter JavaKind elementKind) { + public void delayedGenericArraycopySnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter ArrayCopyTypeCheck arrayTypeCheck, + @ConstantParameter Counters counters, @ConstantParameter JavaKind elementKind) { Object nonNullSrc = GraalDirectives.guardingNonNull(src); Object nonNullDest = GraalDirectives.guardingNonNull(dest); checkArrayTypes(nonNullSrc, nonNullDest, arrayTypeCheck); checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters); incrementLengthCounter(length, counters); - ArrayCopyWithDelayedLoweringNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, workSnippet, elementKind); + // Don't lower until frame states are assigned to deoptimization points. + ArrayCopyWithDelayedLoweringNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, WorkSnippetID.genericArraycopySnippet, GuardsStage.AFTER_FSA, elementKind); } /** * Performs an array copy using the original {@link System#arraycopy} call. Currently, this is - * only used in cases where we already know that the operation will fail. + * only used in cases where we already know that the operation will throw an exception. */ @Snippet - public static void arraycopyNativeSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Counters counters) { + public static void arraycopyNativeExceptionSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Counters counters) { // all checks are done in the native method, so no need to emit additional checks here incrementLengthCounter(length, counters); counters.systemArraycopyCounter.inc(); counters.systemArraycopyCopiedCounter.add(length); System.arraycopy(src, srcPos, dest, destPos, length); + // the call will never return + UnreachableNode.unreachable(); } /** - * @see #doExactArraycopyWithSlowPathWork + * Inlines a loop that performs an {@linkplain BasicArrayCopyNode#isExact() exact} + * element-by-element array copy. The explict loop allows subsequent phases to optimize the + * code. */ @SuppressWarnings("unused") @Snippet(allowPartialIntrinsicArgumentMismatch = true) - public void exactArraycopyWithSlowPathWork(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter JavaKind elementKind, @ConstantParameter LocationIdentity arrayLocation, - @ConstantParameter Counters counters) { - doExactArraycopyWithSlowPathWork(src, srcPos, dest, destPos, length, elementKind, arrayLocation, counters, INJECTED_META_ACCESS); + public void exactArraycopyWithExpandedLoopSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter JavaKind elementKind, + @ConstantParameter LocationIdentity arrayLocation, @ConstantParameter Counters counters) { + doExactArraycopyWithExpandedLoopSnippet(src, srcPos, dest, destPos, length, elementKind, arrayLocation, counters); } /** - * Inlines a loop that performs an {@linkplain ArrayCopy#isExact() exact} element-by-element - * array copy. The explict loop allows subsequent phases to optimize the code. + * @see #exactArraycopyWithExpandedLoopSnippet */ - protected abstract void doExactArraycopyWithSlowPathWork(Object src, int srcPos, Object dest, int destPos, int length, JavaKind elementKind, LocationIdentity arrayLocation, Counters counters, - MetaAccessProvider metaAccess); + protected abstract void doExactArraycopyWithExpandedLoopSnippet(Object src, int srcPos, Object dest, int destPos, int length, JavaKind elementKind, LocationIdentity arrayLocation, + Counters counters); /** - * @see #doCheckcastArraycopyWithSlowPathWork + * Performs an array copy via fast checkcast stub. */ @Snippet(allowPartialIntrinsicArgumentMismatch = true) - public void checkcastArraycopyWithSlowPathWork(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter JavaKind elementKind, + public void checkcastArraycopySnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter JavaKind elementKind, @ConstantParameter LocationIdentity arrayLocation, @ConstantParameter Counters counters) { - doCheckcastArraycopyWithSlowPathWork(src, srcPos, dest, destPos, length, elementKind, arrayLocation, counters); + doCheckcastArraycopySnippet(src, srcPos, dest, destPos, length, elementKind, arrayLocation, counters); } /** - * Performs an array copy via {@link CheckcastArrayCopyCallNode}. - * - * @see CheckcastArrayCopyCallNode + * @see #checkcastArraycopySnippet */ - protected abstract void doCheckcastArraycopyWithSlowPathWork(Object src, int srcPos, Object dest, int destPos, int length, JavaKind elementKind, LocationIdentity arrayLocation, Counters counters); + protected abstract void doCheckcastArraycopySnippet(Object src, int srcPos, Object dest, int destPos, int length, JavaKind elementKind, LocationIdentity arrayLocation, Counters counters); /** - * Performs an array copy via {@link GenericArrayCopyCallNode}. + * Performs a generic array copy with all required type and store checks. * - * @see GenericArrayCopyCallNode - * @see #arraycopyGenericSnippet + * @see #delayedGenericArraycopySnippet + * @see #doGenericArraycopySnippet */ @SuppressWarnings("unused") @Snippet(allowPartialIntrinsicArgumentMismatch = true) - public void genericArraycopyWithSlowPathWork(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter JavaKind elementKind, + public void genericArraycopySnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter JavaKind elementKind, @ConstantParameter LocationIdentity arrayLocation, @ConstantParameter Counters counters) { - // The length > 0 check should not be placed here because generic array copy stub should - // enforce type check. This is fine performance-wise because this snippet is rarely used. - counters.genericArraycopyDifferentTypeCounter.inc(); - counters.genericArraycopyDifferentTypeCopiedCounter.add(length); - int copiedElements = GenericArrayCopyCallNode.genericArraycopy(src, srcPos, dest, destPos, length); - if (probability(SLOW_PATH_PROBABILITY, copiedElements != 0)) { - /* - * the stub doesn't throw the ArrayStoreException, but returns the number of copied - * elements (xor'd with -1). - */ - copiedElements ^= -1; - System.arraycopy(src, srcPos + copiedElements, dest, destPos + copiedElements, length - copiedElements); - } + doGenericArraycopySnippet(src, srcPos, dest, destPos, length, elementKind, arrayLocation, counters); } + /** + * @see #genericArraycopySnippet + */ + protected abstract void doGenericArraycopySnippet(Object src, int srcPos, Object dest, int destPos, int length, JavaKind elementKind, LocationIdentity arrayLocation, Counters counters); + private static void incrementLengthCounter(int length, Counters counters) { if (!IS_BUILDING_NATIVE_IMAGE) { counters.lengthHistogram.inc(length); @@ -391,15 +413,36 @@ void createArraycopyCounter(JavaKind kind, Group counters, Group copiedCounters) } } + /** + * Identifies snippets used for {@linkplain ArrayCopyWithDelayedLoweringNode delayed lowering} + * of {@link ArrayCopyNode}. + * + * @see Templates#getSnippet(WorkSnippetID) + */ + public enum WorkSnippetID { + /** + * @see ArrayCopySnippets#exactArraycopyWithExpandedLoopSnippet + */ + exactArraycopyWithExpandedLoopSnippet, + /** + * @see ArrayCopySnippets#checkcastArraycopySnippet + */ + checkcastArraycopySnippet, + /** + * @see ArrayCopySnippets#genericArraycopySnippet + */ + genericArraycopySnippet; + } + public static class Templates extends SnippetTemplate.AbstractTemplates { - private final SnippetInfo arraycopyGenericSnippet; - private final SnippetInfo arraycopyExactSnippet; + private final SnippetInfo delayedGenericArraycopySnippet; + private final SnippetInfo delayedExactArraycopyWithExpandedLoopSnippet; private final SnippetInfo arraycopyExactStubCallSnippet; - private final SnippetInfo arraycopyCheckcastSnippet; - private final SnippetInfo arraycopyNativeSnippet; - private final SnippetInfo checkcastArraycopyWithSlowPathWork; - private final SnippetInfo genericArraycopyWithSlowPathWork; - private final SnippetInfo exactArraycopyWithSlowPathWork; + private final SnippetInfo delayedCheckcastArraycopySnippet; + private final SnippetInfo arraycopyNativeExceptionSnippet; + private final SnippetInfo checkcastArraycopySnippet; + private final SnippetInfo genericArraycopySnippet; + private final SnippetInfo exactArraycopyWithExpandedLoopSnippet; private final boolean useOriginalArraycopy; private ResolvedJavaMethod originalArraycopy; @@ -411,14 +454,26 @@ public Templates(ArrayCopySnippets receiver, OptionValues options, Iterable TYPE = NodeClass.create(ArrayEqualsNode.class); @@ -199,38 +199,6 @@ public void virtualize(VirtualizerTool tool) { @NodeIntrinsic public static native boolean equals(Object array1, Object array2, int length, @ConstantNodeParameter JavaKind kind); - public static boolean equals(boolean[] array1, boolean[] array2, int length) { - return equals(array1, array2, length, JavaKind.Boolean); - } - - public static boolean equals(byte[] array1, byte[] array2, int length) { - return equals(array1, array2, length, JavaKind.Byte); - } - - public static boolean equals(char[] array1, char[] array2, int length) { - return equals(array1, array2, length, JavaKind.Char); - } - - public static boolean equals(short[] array1, short[] array2, int length) { - return equals(array1, array2, length, JavaKind.Short); - } - - public static boolean equals(int[] array1, int[] array2, int length) { - return equals(array1, array2, length, JavaKind.Int); - } - - public static boolean equals(long[] array1, long[] array2, int length) { - return equals(array1, array2, length, JavaKind.Long); - } - - public static boolean equals(float[] array1, float[] array2, int length) { - return equals(array1, array2, length, JavaKind.Float); - } - - public static boolean equals(double[] array1, double[] array2, int length) { - return equals(array1, array2, length, JavaKind.Double); - } - public ValueNode getArray1() { return array1; } diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/AssertionNode.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/AssertionNode.java index 843449ab0437..98a25eb2bed7 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/AssertionNode.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/AssertionNode.java @@ -27,7 +27,6 @@ import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; -import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; @@ -104,22 +103,13 @@ public Node canonical(CanonicalizerTool tool) { @Override public void lower(LoweringTool tool) { if (!compileTimeAssertion) { - if (GraalOptions.ImmutableCode.getValue(getOptions())) { - // Snippet assertions are disabled for AOT - graph().removeFixed(this); - } else { - tool.getLowerer().lower(this, tool); - } + tool.getLowerer().lower(this, tool); } } @Override public void generate(NodeLIRBuilderTool generator) { assert compileTimeAssertion; - if (GraalOptions.ImmutableCode.getValue(getOptions())) { - // Snippet assertions are disabled for AOT - return; - } if (condition.isConstant()) { if (condition.asJavaConstant().asInt() == 0) { throw new GraalError("%s: failed compile-time assertion: %s", this, message); diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java index 2f82eca0aa12..4f7b02166950 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,61 +30,78 @@ import static org.graalvm.word.LocationIdentity.any; import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.graph.NodeInputList; +import org.graalvm.compiler.nodeinfo.InputType; import org.graalvm.compiler.nodeinfo.NodeCycles; import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.DeoptimizingNode; import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.NodeView; +import org.graalvm.compiler.nodes.StateSplit; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; +import org.graalvm.compiler.nodes.WithExceptionNode; +import org.graalvm.compiler.nodes.java.LoadIndexedNode; +import org.graalvm.compiler.nodes.memory.MemoryAccess; import org.graalvm.compiler.nodes.memory.MemoryKill; -import org.graalvm.compiler.replacements.arraycopy.ArrayCopy; +import org.graalvm.compiler.nodes.memory.SingleMemoryKill; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.Virtualizable; +import org.graalvm.compiler.nodes.spi.VirtualizerTool; +import org.graalvm.compiler.nodes.type.StampTool; +import org.graalvm.compiler.nodes.virtual.VirtualArrayNode; +import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; import org.graalvm.word.LocationIdentity; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaType; /** * Base class for nodes that intrinsify {@link System#arraycopy}. */ @NodeInfo(cycles = NodeCycles.CYCLES_UNKNOWN, size = SIZE_64) -public class BasicArrayCopyNode extends AbstractMemoryCheckpoint implements ArrayCopy { +public abstract class BasicArrayCopyNode extends WithExceptionNode implements StateSplit, Virtualizable, SingleMemoryKill, MemoryAccess, Lowerable, DeoptimizingNode.DeoptDuring { public static final NodeClass TYPE = NodeClass.create(BasicArrayCopyNode.class); - @Input NodeInputList args; + @Input ValueNode src; + @Input ValueNode srcPos; + @Input ValueNode dest; + @Input ValueNode destPos; + @Input ValueNode length; @OptionalInput(State) FrameState stateDuring; @OptionalInput(Memory) protected MemoryKill lastLocationAccess; + @OptionalInput(InputType.State) protected FrameState stateAfter; + protected JavaKind elementKind; protected int bci; - public BasicArrayCopyNode(NodeClass type, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind, int bci) { + public BasicArrayCopyNode(NodeClass type, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind, int bci) { super(type, StampFactory.forKind(JavaKind.Void)); this.bci = bci; - this.args = new NodeInputList<>(this, new ValueNode[]{src, srcPos, dest, destPos, length}); + this.src = src; + this.srcPos = srcPos; + this.dest = dest; + this.destPos = destPos; + this.length = length; this.elementKind = elementKind != JavaKind.Illegal ? elementKind : null; } - public BasicArrayCopyNode(NodeClass type, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind) { + public BasicArrayCopyNode(NodeClass type, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind) { this(type, src, srcPos, dest, destPos, length, elementKind, BytecodeFrame.INVALID_FRAMESTATE_BCI); } - @Override - public NodeInputList args() { - return args; - } - - @Override public int getBci() { return bci; } - @Override public JavaKind getElementKind() { return elementKind; } @@ -123,4 +140,178 @@ public void setStateDuring(FrameState stateDuring) { updateUsages(this.stateDuring, stateDuring); this.stateDuring = stateDuring; } + + @Override + public FrameState stateAfter() { + return stateAfter; + } + + @Override + public void setStateAfter(FrameState x) { + assert x == null || x.isAlive() : "frame state must be in a graph"; + updateUsages(stateAfter, x); + stateAfter = x; + } + + @Override + public boolean hasSideEffect() { + return true; + } + + public static JavaKind selectComponentKind(BasicArrayCopyNode arraycopy) { + ResolvedJavaType srcType = StampTool.typeOrNull(arraycopy.getSource().stamp(NodeView.DEFAULT)); + ResolvedJavaType destType = StampTool.typeOrNull(arraycopy.getDestination().stamp(NodeView.DEFAULT)); + + if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) { + return null; + } + if (!destType.getComponentType().isAssignableFrom(srcType.getComponentType())) { + return null; + } + if (!arraycopy.isExact()) { + return null; + } + return srcType.getComponentType().getJavaKind(); + } + + public ValueNode getSource() { + return src; + } + + public ValueNode getSourcePosition() { + return srcPos; + } + + public ValueNode getDestination() { + return dest; + } + + public ValueNode getDestinationPosition() { + return destPos; + } + + public ValueNode getLength() { + return length; + } + + public static boolean checkBounds(int position, int length, VirtualObjectNode virtualObject) { + assert length >= 0; + return position >= 0 && position <= virtualObject.entryCount() - length; + } + + public static boolean checkEntryTypes(int srcPos, int length, VirtualObjectNode src, ResolvedJavaType destComponentType, VirtualizerTool tool) { + if (destComponentType.getJavaKind() == JavaKind.Object && !destComponentType.isJavaLangObject()) { + for (int i = 0; i < length; i++) { + ValueNode entry = tool.getEntry(src, srcPos + i); + ResolvedJavaType type = StampTool.typeOrNull(entry); + if (type == null || !destComponentType.isAssignableFrom(type)) { + return false; + } + } + } + return true; + } + + /* + * Returns true if this copy doesn't require store checks. Trivially true for primitive arrays. + */ + public boolean isExact() { + ResolvedJavaType srcType = StampTool.typeOrNull(getSource().stamp(NodeView.DEFAULT)); + ResolvedJavaType destType = StampTool.typeOrNull(getDestination().stamp(NodeView.DEFAULT)); + if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) { + return false; + } + if ((srcType.getComponentType().getJavaKind().isPrimitive() && destType.getComponentType().equals(srcType.getComponentType())) || getSource() == getDestination()) { + return true; + } + + if (StampTool.isExactType(getDestination().stamp(NodeView.DEFAULT))) { + if (destType != null && destType.isAssignableFrom(srcType)) { + return true; + } + } + return false; + } + + @Override + public void virtualize(VirtualizerTool tool) { + ValueNode sourcePosition = tool.getAlias(getSourcePosition()); + ValueNode destinationPosition = tool.getAlias(getDestinationPosition()); + ValueNode replacedLength = tool.getAlias(getLength()); + + if (sourcePosition.isConstant() && destinationPosition.isConstant() && replacedLength.isConstant()) { + int srcPosInt = sourcePosition.asJavaConstant().asInt(); + int destPosInt = destinationPosition.asJavaConstant().asInt(); + int len = replacedLength.asJavaConstant().asInt(); + ValueNode destAlias = tool.getAlias(getDestination()); + + if (destAlias instanceof VirtualArrayNode) { + VirtualArrayNode destVirtual = (VirtualArrayNode) destAlias; + if (len < 0 || !checkBounds(destPosInt, len, destVirtual)) { + return; + } + ValueNode srcAlias = tool.getAlias(getSource()); + + if (srcAlias instanceof VirtualObjectNode) { + if (!(srcAlias instanceof VirtualArrayNode)) { + return; + } + VirtualArrayNode srcVirtual = (VirtualArrayNode) srcAlias; + if (destVirtual.componentType().getJavaKind() != srcVirtual.componentType().getJavaKind()) { + return; + } + if (!checkBounds(srcPosInt, len, srcVirtual)) { + return; + } + if (!checkEntryTypes(srcPosInt, len, srcVirtual, destVirtual.type().getComponentType(), tool)) { + return; + } + if (srcVirtual == destVirtual && srcPosInt < destPosInt) { + // must copy backwards to avoid losing elements + for (int i = len - 1; i >= 0; i--) { + tool.setVirtualEntry(destVirtual, destPosInt + i, tool.getEntry(srcVirtual, srcPosInt + i)); + } + } else { + for (int i = 0; i < len; i++) { + tool.setVirtualEntry(destVirtual, destPosInt + i, tool.getEntry(srcVirtual, srcPosInt + i)); + } + } + tool.delete(); + DebugContext debug = this.asNode().getDebug(); + if (debug.isLogEnabled()) { + debug.log("virtualized arraycopy(%s, %d, %s, %d, %d)", getSource(), srcPosInt, getDestination(), destPosInt, len); + } + } else { + ResolvedJavaType sourceType = StampTool.typeOrNull(srcAlias); + if (sourceType == null || !sourceType.isArray()) { + return; + } + ResolvedJavaType sourceComponentType = sourceType.getComponentType(); + ResolvedJavaType destComponentType = destVirtual.type().getComponentType(); + if (!sourceComponentType.equals(destComponentType)) { + return; + } + for (int i = 0; i < len; i++) { + LoadIndexedNode load = new LoadIndexedNode(this.asNode().graph().getAssumptions(), srcAlias, ConstantNode.forInt(i + srcPosInt, this.asNode().graph()), null, + destComponentType.getJavaKind()); + load.setNodeSourcePosition(this.asNode().getNodeSourcePosition()); + tool.addNode(load); + tool.setVirtualEntry(destVirtual, destPosInt + i, load); + } + tool.delete(); + } + } + } + } + + @Override + public boolean canDeoptimize() { + return true; + } + + @Override + public void computeStateDuring(FrameState currentStateAfter) { + FrameState newStateDuring = currentStateAfter.duplicateModifiedDuringCall(getBci(), asNode().getStackKind()); + setStateDuring(newStateDuring); + } } diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java index fcbc4dc80e08..7cb6319c1ec9 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java @@ -32,7 +32,7 @@ import org.graalvm.compiler.nodes.ValueNode; @NodeInfo(cycles = NodeCycles.CYCLES_UNKNOWN, cyclesRationale = "see rationale in MacroNode", size = SIZE_8) -public abstract class BasicObjectCloneNode extends MacroStateSplitNode implements ObjectClone { +public abstract class BasicObjectCloneNode extends MacroNode implements ObjectClone { public static final NodeClass TYPE = NodeClass.create(BasicObjectCloneNode.class); diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitScanForwardNode.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitScanForwardNode.java index eaaf474d1a07..e222c41c15d1 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitScanForwardNode.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitScanForwardNode.java @@ -32,7 +32,6 @@ import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ConstantNode; @@ -40,6 +39,7 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.UnaryNode; import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable; +import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import jdk.vm.ci.code.CodeUtil; @@ -119,24 +119,6 @@ public static int scan(int v) { return scan(0xffffffffL & v); } - /** - * Raw intrinsic for bsf instruction. - * - * @param v - * @return number of trailing zeros or an undefined value if {@code v} == 0. - */ - @NodeIntrinsic - public static native int unsafeScan(long v); - - /** - * Raw intrinsic for bsf instruction. - * - * @param v - * @return number of trailing zeros or an undefined value if {@code v} == 0. - */ - @NodeIntrinsic - public static native int unsafeScan(int v); - @Override public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) { builder.setResult(this, gen.emitBitScanForward(builder.operand(getValue()))); diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitScanReverseNode.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitScanReverseNode.java index f9b3f9ddab00..7c334f7b8e7f 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitScanReverseNode.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BitScanReverseNode.java @@ -32,7 +32,6 @@ import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ConstantNode; @@ -40,6 +39,7 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.UnaryNode; import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable; +import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import jdk.vm.ci.code.CodeUtil; @@ -110,24 +110,6 @@ public static int scan(int v) { return 31 - Integer.numberOfLeadingZeros(v); } - /** - * Raw intrinsic for bsr instruction. - * - * @param v - * @return index of first set bit or an undefined value if {@code v} == 0. - */ - @NodeIntrinsic - public static native int unsafeScan(int v); - - /** - * Raw intrinsic for bsr instruction. - * - * @param v - * @return index of first set bit or an undefined value if {@code v} == 0. - */ - @NodeIntrinsic - public static native int unsafeScan(long v); - @Override public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) { builder.setResult(this, gen.emitBitScanReverse(builder.operand(getValue()))); diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/FallbackInvokeWithExceptionNode.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/FallbackInvokeWithExceptionNode.java index cba202eb723b..690d1a107db8 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/FallbackInvokeWithExceptionNode.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/FallbackInvokeWithExceptionNode.java @@ -39,12 +39,12 @@ import org.graalvm.word.LocationIdentity; /** - * Placeholder for a fallback call from a {@link MacroStateSplitWithExceptionNode}. + * Placeholder for a fallback call from a {@link MacroWithExceptionNode}. * * The {@link #fallbackFunctionCall()} intrinsic can be used in snippets that lower a - * {@link MacroStateSplitWithExceptionNode}. The {@link FallbackInvokeWithExceptionNode} will be - * replaced with the {@linkplain MacroStateSplitWithExceptionNode#createInvoke original call} of the - * macro node. This can be useful for handling exceptional and/or slow path cases. + * {@link MacroWithExceptionNode}. The {@link FallbackInvokeWithExceptionNode} will be replaced with + * the {@linkplain MacroWithExceptionNode#createInvoke original call} of the macro node. This can be + * useful for handling exceptional and/or slow path cases. * * Currently, only one {@link FallbackInvokeWithExceptionNode} is allowed per snippet. */ diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/IdentityHashCodeNode.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/IdentityHashCodeNode.java index b2804437f2c4..1e95f7a8a239 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/IdentityHashCodeNode.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/IdentityHashCodeNode.java @@ -24,8 +24,6 @@ */ package org.graalvm.compiler.replacements.nodes; -import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; - import org.graalvm.compiler.core.common.type.AbstractObjectStamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.Node; @@ -76,9 +74,6 @@ public Node canonical(CanonicalizerTool tool) { if (object.isConstant()) { assert object.stamp(NodeView.DEFAULT) instanceof AbstractObjectStamp; JavaConstant c = (JavaConstant) object.asConstant(); - if (ImmutableCode.getValue(tool.getOptions())) { - return this; - } int identityHashCode; if (c.isNull()) { diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroInvokable.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroInvokable.java index 093b1b7cabb6..8a84ca1a5086 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroInvokable.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroInvokable.java @@ -34,8 +34,10 @@ import org.graalvm.compiler.nodes.Invokable; import org.graalvm.compiler.nodes.Invoke; import org.graalvm.compiler.nodes.InvokeNode; +import org.graalvm.compiler.nodes.StateSplit; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.SingleMemoryKill; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.phases.common.CanonicalizerPhase; @@ -57,11 +59,10 @@ * used as a replacement. *
  • If a {@link MethodSubstitution} for the target method is found, this substitution is used as * a replacement.
  • - *
  • Otherwise, the macro node is replaced with an {@link InvokeNode}. Note that this is only - * possible if the macro node is a {@link MacroStateSplitNode}.
  • + *
  • Otherwise, the macro node is replaced with an {@link InvokeNode}.
  • * */ -public interface MacroInvokable extends Invokable, Lowerable { +public interface MacroInvokable extends Invokable, Lowerable, StateSplit, SingleMemoryKill { CallTargetNode.InvokeKind getInvokeKind(); diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java index c5dfbe023d47..84b884782a90 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java @@ -33,9 +33,9 @@ import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.NodeInputList; +import org.graalvm.compiler.nodeinfo.InputType; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; -import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.Invoke; @@ -61,6 +61,7 @@ public abstract class MacroNode extends FixedWithNextNode implements MacroInvoka public static final NodeClass TYPE = NodeClass.create(MacroNode.class); @Input protected NodeInputList arguments; + @OptionalInput(InputType.State) protected FrameState stateAfter; protected final int bci; protected final ResolvedJavaMethod callerMethod; @@ -154,18 +155,37 @@ public InvokeKind getInvokeKind() { return invokeKind; } - protected FrameState stateAfter() { - return null; + @Override + public FrameState stateAfter() { + return stateAfter; } @Override - protected void afterClone(Node other) { - updateInliningLogAfterClone(other); + public void setStateAfter(FrameState x) { + assert x == null || x.isAlive() : "frame state must be in a graph"; + updateUsages(stateAfter, x); + stateAfter = x; + } + + @Override + public final boolean hasSideEffect() { + return true; + } + + /** + * Returns {@link LocationIdentity#any()}. This node needs to kill any location because it might + * get {@linkplain #replaceWithInvoke() replaced with an invoke} and + * {@link InvokeNode#getKilledLocationIdentity()} kills {@link LocationIdentity#any()} and the + * kill location must not get broader. + */ + @Override + public final LocationIdentity getKilledLocationIdentity() { + return LocationIdentity.any(); } @Override - public FixedNode asFixedNode() { - return this; + protected void afterClone(Node other) { + updateInliningLogAfterClone(other); } @Override diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java deleted file mode 100644 index c6596ba6c23c..000000000000 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.replacements.nodes; - -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodeinfo.InputType; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.FrameState; -import org.graalvm.compiler.nodes.Invoke; -import org.graalvm.compiler.nodes.InvokeNode; -import org.graalvm.compiler.nodes.StateSplit; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.java.MethodCallTargetNode; -import org.graalvm.compiler.nodes.memory.MemoryKill; -import org.graalvm.compiler.nodes.memory.SingleMemoryKill; -import org.graalvm.word.LocationIdentity; - -import jdk.vm.ci.code.BytecodeFrame; - -/** - * This is an extension of {@link MacroNode} that is a {@link StateSplit} and a {@link MemoryKill}. - */ -@NodeInfo -public abstract class MacroStateSplitNode extends MacroNode implements StateSplit, SingleMemoryKill { - - public static final NodeClass TYPE = NodeClass.create(MacroStateSplitNode.class); - @OptionalInput(InputType.State) protected FrameState stateAfter; - - protected MacroStateSplitNode(NodeClass c, MacroParams p) { - super(c, p); - } - - @Override - public FrameState stateAfter() { - return stateAfter; - } - - @Override - public void setStateAfter(FrameState x) { - assert x == null || x.isAlive() : "frame state must be in a graph"; - updateUsages(stateAfter, x); - stateAfter = x; - } - - @Override - public boolean hasSideEffect() { - return true; - } - - @Override - public LocationIdentity getKilledLocationIdentity() { - return LocationIdentity.any(); - } - - protected void replaceSnippetInvokes(StructuredGraph snippetGraph) { - for (MethodCallTargetNode call : snippetGraph.getNodes(MethodCallTargetNode.TYPE)) { - Invoke invoke = call.invoke(); - if (!call.targetMethod().equals(getTargetMethod())) { - throw new GraalError("unexpected invoke %s in snippet", getClass().getSimpleName()); - } - assert invoke.stateAfter().bci == BytecodeFrame.AFTER_BCI; - // Here we need to fix the bci of the invoke - InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.callTarget(), bci(), invoke.getKilledLocationIdentity())); - newInvoke.setStateAfter(invoke.stateAfter()); - snippetGraph.replaceFixedWithFixed((InvokeNode) invoke.asNode(), newInvoke); - } - } -} diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitWithExceptionNode.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroWithExceptionNode.java similarity index 87% rename from compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitWithExceptionNode.java rename to compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroWithExceptionNode.java index 29cf0e41362e..6a5dce46af54 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitWithExceptionNode.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroWithExceptionNode.java @@ -36,15 +36,12 @@ import org.graalvm.compiler.nodeinfo.InputType; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; -import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.Invoke; import org.graalvm.compiler.nodes.InvokeWithExceptionNode; -import org.graalvm.compiler.nodes.StateSplit; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.WithExceptionNode; import org.graalvm.compiler.nodes.java.MethodCallTargetNode; -import org.graalvm.compiler.nodes.memory.SingleMemoryKill; import org.graalvm.compiler.replacements.nodes.MacroNode.MacroParams; import org.graalvm.word.LocationIdentity; @@ -52,12 +49,12 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; /** - * This duplicates a {@link MacroStateSplitNode} using {@link WithExceptionNode} as a base class. + * This duplicates a {@link MacroNode} using {@link WithExceptionNode} as a base class. * * See the documentation of {@link MacroInvokable} for more information. * * @see MacroInvokable - * @see MacroStateSplitNode + * @see MacroNode */ //@formatter:off @NodeInfo(cycles = CYCLES_UNKNOWN, @@ -65,9 +62,9 @@ size = SIZE_UNKNOWN, sizeRationale = "If this node is not optimized away it will be lowered to a call, which we cannot estimate") //@formatter:on -public abstract class MacroStateSplitWithExceptionNode extends WithExceptionNode implements MacroInvokable, StateSplit, SingleMemoryKill { +public abstract class MacroWithExceptionNode extends WithExceptionNode implements MacroInvokable { - public static final NodeClass TYPE = NodeClass.create(MacroStateSplitWithExceptionNode.class); + public static final NodeClass TYPE = NodeClass.create(MacroWithExceptionNode.class); @Input protected NodeInputList arguments; @OptionalInput(InputType.State) protected FrameState stateAfter; @@ -77,7 +74,7 @@ public abstract class MacroStateSplitWithExceptionNode extends WithExceptionNode protected final InvokeKind invokeKind; protected final StampPair returnStamp; - protected MacroStateSplitWithExceptionNode(NodeClass c, MacroParams p) { + protected MacroWithExceptionNode(NodeClass c, MacroParams p) { super(c, p.returnStamp != null ? p.returnStamp.getTrustedStamp() : null); this.arguments = new NodeInputList<>(this, p.arguments); this.bci = p.bci; @@ -119,11 +116,6 @@ protected void afterClone(Node other) { updateInliningLogAfterClone(other); } - @Override - public FixedNode asFixedNode() { - return this; - } - @Override @SuppressWarnings("try") public Invoke replaceWithInvoke() { @@ -134,10 +126,6 @@ public Invoke replaceWithInvoke() { } } - public LocationIdentity getLocationIdentity() { - return LocationIdentity.any(); - } - protected InvokeWithExceptionNode createInvoke() { return createInvoke(this); } @@ -175,10 +163,15 @@ public void setStateAfter(FrameState x) { } @Override - public boolean hasSideEffect() { + public final boolean hasSideEffect() { return true; } + /** + * @see MacroNode#getKilledLocationIdentity() + * + * FIXME: make this final once [GR-32638] is fixed + */ @Override public LocationIdentity getKilledLocationIdentity() { return LocationIdentity.any(); diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MethodHandleNode.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MethodHandleNode.java index c925cb20beec..abd90e9ac8e9 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MethodHandleNode.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MethodHandleNode.java @@ -76,7 +76,7 @@ * Node for invocation methods defined on the class {@link MethodHandle}. */ @NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "see MacroNode", size = SIZE_UNKNOWN, sizeRationale = "see MacroNode") -public final class MethodHandleNode extends MacroStateSplitNode implements Simplifiable { +public final class MethodHandleNode extends MacroNode implements Simplifiable { public static final NodeClass TYPE = NodeClass.create(MethodHandleNode.class); protected final IntrinsicMethod intrinsicMethod; diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ProfileBooleanNode.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ProfileBooleanNode.java index 478bcdf8e05e..07edfde9db91 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ProfileBooleanNode.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ProfileBooleanNode.java @@ -46,7 +46,7 @@ import jdk.vm.ci.meta.JavaConstant; @NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN) -public class ProfileBooleanNode extends MacroStateSplitNode implements Simplifiable { +public class ProfileBooleanNode extends MacroNode implements Simplifiable { public static final NodeClass TYPE = NodeClass.create(ProfileBooleanNode.class); private final ConstantReflectionProvider constantProvider; diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/PureFunctionMacroNode.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/PureFunctionMacroNode.java index feaaf177c047..3e0ca1fdcd5b 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/PureFunctionMacroNode.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/PureFunctionMacroNode.java @@ -40,7 +40,7 @@ * {@link System#identityHashCode(Object)}. */ @NodeInfo -public abstract class PureFunctionMacroNode extends MacroStateSplitNode implements Canonicalizable { +public abstract class PureFunctionMacroNode extends MacroNode implements Canonicalizable { public static final NodeClass TYPE = NodeClass.create(PureFunctionMacroNode.class); diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ReflectionGetCallerClassNode.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ReflectionGetCallerClassNode.java index 11d72e287572..7af8659f1f48 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ReflectionGetCallerClassNode.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ReflectionGetCallerClassNode.java @@ -42,7 +42,7 @@ import jdk.vm.ci.meta.ResolvedJavaType; @NodeInfo -public abstract class ReflectionGetCallerClassNode extends MacroStateSplitNode implements Canonicalizable, Lowerable { +public abstract class ReflectionGetCallerClassNode extends MacroNode implements Canonicalizable, Lowerable { public static final NodeClass TYPE = NodeClass.create(ReflectionGetCallerClassNode.class); diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/VirtualizableInvokeMacroNode.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/VirtualizableInvokeMacroNode.java index f2d10adbea9c..78c14a10e152 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/VirtualizableInvokeMacroNode.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/VirtualizableInvokeMacroNode.java @@ -36,7 +36,7 @@ * analysis. */ @NodeInfo -public class VirtualizableInvokeMacroNode extends MacroStateSplitNode implements Virtualizable { +public class VirtualizableInvokeMacroNode extends MacroNode implements Virtualizable { public static final NodeClass TYPE = NodeClass.create(VirtualizableInvokeMacroNode.class); diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ZeroMemoryNode.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ZeroMemoryNode.java index 7d2ece935f3c..f3e41dc2dceb 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ZeroMemoryNode.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ZeroMemoryNode.java @@ -33,6 +33,7 @@ import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.memory.FixedAccessNode; +import org.graalvm.compiler.nodes.memory.SingleMemoryKill; import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; import org.graalvm.compiler.nodes.spi.LIRLowerable; @@ -44,7 +45,7 @@ * Zeros a chunk of memory. */ @NodeInfo(nameTemplate = "ZeroMemory#{p#location/s}", allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_8, size = SIZE_8) -public class ZeroMemoryNode extends FixedAccessNode implements LIRLowerable { +public class ZeroMemoryNode extends FixedAccessNode implements LIRLowerable, SingleMemoryKill { public static final NodeClass TYPE = NodeClass.create(ZeroMemoryNode.class); @Input ValueNode length; @@ -72,4 +73,9 @@ public boolean canNullCheck() { @NodeIntrinsic public static native void zero(Word address, long length, @ConstantNodeParameter boolean isAligned, @ConstantNodeParameter LocationIdentity locationIdentity); + + @Override + public LocationIdentity getKilledLocationIdentity() { + return location; + } } diff --git a/compiler/src/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalUnsafeAccess.java b/compiler/src/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalUnsafeAccess.java index 349913065235..2903f78d8d32 100644 --- a/compiler/src/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalUnsafeAccess.java +++ b/compiler/src/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalUnsafeAccess.java @@ -59,6 +59,7 @@ private static Unsafe initUnsafe() { * @throws SecurityException if a security manager is present and it denies * {@link RuntimePermission}("accessUnsafe") */ + @SuppressWarnings("deprecation") // checkPermission deprecated starting with JDK 17 public static Unsafe getUnsafe() { SecurityManager sm = System.getSecurityManager(); if (sm != null) { diff --git a/compiler/src/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java b/compiler/src/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java index 14d3de8bd567..a44688f1b45e 100644 --- a/compiler/src/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java +++ b/compiler/src/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java @@ -278,7 +278,7 @@ public static Subprocess java(List vmArgs, String... mainClassAndArgs) t * @param mainClassAndArgs the main class and its arguments */ public static Subprocess java(List vmArgs, List mainClassAndArgs) throws IOException, InterruptedException { - return javaHelper(vmArgs, null, mainClassAndArgs, null); + return javaHelper(vmArgs, null, null, mainClassAndArgs, null); } /** @@ -289,7 +289,20 @@ public static Subprocess java(List vmArgs, List mainClassAndArgs * @param timeout the timeout duration until the process is killed */ public static Subprocess java(List vmArgs, List mainClassAndArgs, Duration timeout) throws IOException, InterruptedException { - return javaHelper(vmArgs, null, mainClassAndArgs, timeout); + return javaHelper(vmArgs, null, null, mainClassAndArgs, timeout); + } + + /** + * Executes a Java subprocess with a timeout in the specified working directory. + * + * @param vmArgs the VM arguments + * @param workingDir the working directory of the subprocess. If null, the working directory of + * the current process is used. + * @param mainClassAndArgs the main class and its arguments + * @param timeout the timeout duration until the process is killed + */ + public static Subprocess java(List vmArgs, File workingDir, List mainClassAndArgs, Duration timeout) throws IOException, InterruptedException { + return javaHelper(vmArgs, null, workingDir, mainClassAndArgs, timeout); } /** @@ -311,19 +324,23 @@ public static Subprocess java(List vmArgs, Map env, Stri * @param mainClassAndArgs the main class and its arguments */ public static Subprocess java(List vmArgs, Map env, List mainClassAndArgs) throws IOException, InterruptedException { - return javaHelper(vmArgs, env, mainClassAndArgs, null); + return javaHelper(vmArgs, env, null, mainClassAndArgs, null); } /** * Executes a Java subprocess. * - * @param vmArgs the VM arguments + * @param vmArgs the VM arguments. If {@code vmArgs} contains {@link #PACKAGE_OPENING_OPTIONS}, + * the argument is replaced with arguments to do package opening (see + * {@link SubprocessUtil#getPackageOpeningOptions()} * @param env the environment variables + * @param workingDir the working directory of the subprocess. If null, the working directory of + * the current process is used. * @param mainClassAndArgs the main class and its arguments * @param timeout the duration to wait for the process to finish. If null, the calling thread * waits for the process indefinitely. */ - private static Subprocess javaHelper(List vmArgs, Map env, List mainClassAndArgs, Duration timeout) throws IOException, InterruptedException { + private static Subprocess javaHelper(List vmArgs, Map env, File workingDir, List mainClassAndArgs, Duration timeout) throws IOException, InterruptedException { List command = new ArrayList<>(vmArgs.size()); Path packageOpeningOptionsArgumentsFile = null; for (String vmArg : vmArgs) { @@ -341,46 +358,68 @@ private static Subprocess javaHelper(List vmArgs, Map en } } command.addAll(mainClassAndArgs); + try { + return process(command, env, workingDir, timeout); + } finally { + if (packageOpeningOptionsArgumentsFile != null) { + if (!Boolean.getBoolean(KEEP_TEMPORARY_ARGUMENT_FILES_PROPERTY_NAME)) { + Files.delete(packageOpeningOptionsArgumentsFile); + } + } + } + } + + /** + * Executes a command in a subprocess. + * + * @param command the command to be executed in a separate process. + * @param env environment variables of the subprocess. If null, no environment variables are + * passed. + * @param workingDir the working directory of the subprocess. If null, the working directory of + * the current process is used. + * @param timeout the duration to wait for the process to finish. When the timeout is reached, + * the subprocess is terminated forcefully. If the timeout is null, the calling + * thread waits for the process indefinitely. + */ + public static Subprocess process(List command, Map env, File workingDir, Duration timeout) throws IOException, InterruptedException { ProcessBuilder processBuilder = new ProcessBuilder(command); + if (workingDir != null) { + processBuilder.directory(workingDir); + } if (env != null) { Map processBuilderEnv = processBuilder.environment(); processBuilderEnv.putAll(env); } processBuilder.redirectErrorStream(true); - try { - Process process = processBuilder.start(); - BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream())); - List output = new ArrayList<>(); - if (timeout == null) { - String line; - while ((line = stdout.readLine()) != null) { - output.add(line); - } - return new Subprocess(command, env, process.waitFor(), output, false); - } else { - // The subprocess might produce output forever. We need to grab the output in a - // separate thread, so we can terminate the process after the timeout if necessary. - Thread outputReader = new Thread(() -> { - try { - String line; - while ((line = stdout.readLine()) != null) { - output.add(line); - } - } catch (IOException e) { - // happens when the process ends - } - }); - outputReader.start(); - boolean finishedOnTime = process.waitFor(timeout.getSeconds(), TimeUnit.SECONDS); - int exitCode = process.destroyForcibly().waitFor(); - return new Subprocess(command, env, exitCode, output, !finishedOnTime); + Process process = processBuilder.start(); + BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream())); + List output = new ArrayList<>(); + if (timeout == null) { + String line; + while ((line = stdout.readLine()) != null) { + output.add(line); } - } finally { - if (packageOpeningOptionsArgumentsFile != null) { - if (!Boolean.getBoolean(KEEP_TEMPORARY_ARGUMENT_FILES_PROPERTY_NAME)) { - Files.delete(packageOpeningOptionsArgumentsFile); + return new Subprocess(command, env, process.waitFor(), output, false); + } else { + // The subprocess might produce output forever. We need to grab the output in a + // separate thread, so we can terminate the process after the timeout if necessary. + Thread outputReader = new Thread(() -> { + try { + String line; + while ((line = stdout.readLine()) != null) { + output.add(line); + } + } catch (IOException e) { + // happens when the process ends } + }); + outputReader.start(); + boolean finishedOnTime = process.waitFor(timeout.getSeconds(), TimeUnit.SECONDS); + if (!finishedOnTime) { + process.destroyForcibly().waitFor(); } + outputReader.join(); + return new Subprocess(command, env, process.exitValue(), output, !finishedOnTime); } } diff --git a/compiler/src/org.graalvm.compiler.truffle.common.hotspot.libgraal/src/org/graalvm/compiler/truffle/common/hotspot/libgraal/TruffleFromLibGraal.java b/compiler/src/org.graalvm.compiler.truffle.common.hotspot.libgraal/src/org/graalvm/compiler/truffle/common/hotspot/libgraal/TruffleFromLibGraal.java index 27676762aa98..40a663c7bedd 100644 --- a/compiler/src/org.graalvm.compiler.truffle.common.hotspot.libgraal/src/org/graalvm/compiler/truffle/common/hotspot/libgraal/TruffleFromLibGraal.java +++ b/compiler/src/org.graalvm.compiler.truffle.common.hotspot.libgraal/src/org/graalvm/compiler/truffle/common/hotspot/libgraal/TruffleFromLibGraal.java @@ -112,7 +112,7 @@ enum Id implements FromLibGraalId { Log(void.class, Object.class, String.class, Object.class, String.class), OnCodeInstallation(void.class, Object.class, Object.class, long.class), OnCompilationFailed(void.class, Object.class, Supplier.class, boolean.class, boolean.class, boolean.class, boolean.class), - OnCompilationRetry(void.class, Object.class, Object.class, int.class), + OnCompilationRetry(void.class, Object.class, Object.class, Object.class), OnFailure(void.class, Object.class, Object.class, String.class, boolean.class, boolean.class, int.class), OnGraalTierFinished(void.class, Object.class, Object.class, long.class), OnSuccess(void.class, Object.class, Object.class, Object.class, long.class, long.class, int.class), diff --git a/compiler/src/org.graalvm.compiler.truffle.common/src/org/graalvm/compiler/truffle/common/TruffleCompilationTask.java b/compiler/src/org.graalvm.compiler.truffle.common/src/org/graalvm/compiler/truffle/common/TruffleCompilationTask.java index db8757acfe78..cb318c15b4cb 100644 --- a/compiler/src/org.graalvm.compiler.truffle.common/src/org/graalvm/compiler/truffle/common/TruffleCompilationTask.java +++ b/compiler/src/org.graalvm.compiler.truffle.common/src/org/graalvm/compiler/truffle/common/TruffleCompilationTask.java @@ -52,4 +52,20 @@ default int tier() { TruffleInliningData inliningData(); boolean hasNextTier(); + + default long time() { + return 0; + } + + default double weight() { + return Double.NaN; + } + + default double rate() { + return Double.NaN; + } + + default int queueChange() { + return 0; + } } diff --git a/compiler/src/org.graalvm.compiler.truffle.common/src/org/graalvm/compiler/truffle/common/TruffleCompilerListener.java b/compiler/src/org.graalvm.compiler.truffle.common/src/org/graalvm/compiler/truffle/common/TruffleCompilerListener.java index 0f69111afa87..65e4d194cd3e 100644 --- a/compiler/src/org.graalvm.compiler.truffle.common/src/org/graalvm/compiler/truffle/common/TruffleCompilerListener.java +++ b/compiler/src/org.graalvm.compiler.truffle.common/src/org/graalvm/compiler/truffle/common/TruffleCompilerListener.java @@ -172,8 +172,8 @@ default void onFailure(CompilableTruffleAST compilable, String reason, boolean b * @deprecated use {@link #onCompilationRetry(CompilableTruffleAST, int)} */ @Deprecated - default void onCompilationRetry(CompilableTruffleAST compilable) { - onCompilationRetry(compilable, 0); + @SuppressWarnings("unused") + default void onCompilationRetry(CompilableTruffleAST compilable, int tier) { } /** @@ -181,8 +181,9 @@ default void onCompilationRetry(CompilableTruffleAST compilable) { * compilation problem. * * @param compilable the Truffle AST which is going to be re-compiled. - * @param tier Which compilation tier is in question. + * @param task Which compilation task is in question. */ - default void onCompilationRetry(CompilableTruffleAST compilable, int tier) { + default void onCompilationRetry(CompilableTruffleAST compilable, TruffleCompilationTask task) { + onCompilationRetry(compilable, task.tier()); } } diff --git a/compiler/src/org.graalvm.compiler.truffle.compiler.hotspot.amd64/src/org/graalvm/compiler/truffle/compiler/hotspot/amd64/AMD64TruffleCallBoundaryInstrumentationFactory.java b/compiler/src/org.graalvm.compiler.truffle.compiler.hotspot.amd64/src/org/graalvm/compiler/truffle/compiler/hotspot/amd64/AMD64TruffleCallBoundaryInstrumentationFactory.java index 1609955b730a..94f310b3d837 100644 --- a/compiler/src/org.graalvm.compiler.truffle.compiler.hotspot.amd64/src/org/graalvm/compiler/truffle/compiler/hotspot/amd64/AMD64TruffleCallBoundaryInstrumentationFactory.java +++ b/compiler/src/org.graalvm.compiler.truffle.compiler.hotspot.amd64/src/org/graalvm/compiler/truffle/compiler/hotspot/amd64/AMD64TruffleCallBoundaryInstrumentationFactory.java @@ -80,7 +80,7 @@ protected void injectTailCallCode(int installedCodeOffset, int entryPointOffset) masm.movl(spillRegister, new AMD64Address(thisRegister, installedCodeOffset), true); assert masm.position() - pos >= AMD64HotSpotBackend.PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE; CompressEncoding encoding = config.getOopEncoding(); - Register heapBaseRegister = AMD64Move.UncompressPointerOp.hasBase(options, encoding) ? registers.getHeapBaseRegister() : Register.None; + Register heapBaseRegister = AMD64Move.UncompressPointerOp.hasBase(encoding) ? registers.getHeapBaseRegister() : Register.None; AMD64Move.UncompressPointerOp.emitUncompressCode(masm, spillRegister, encoding.getShift(), heapBaseRegister, true); } else { // First instruction must be at least 5 bytes long to be safe for diff --git a/compiler/src/org.graalvm.compiler.truffle.compiler.hotspot.libgraal/src/org/graalvm/compiler/truffle/compiler/hotspot/libgraal/HSTruffleCompilerListener.java b/compiler/src/org.graalvm.compiler.truffle.compiler.hotspot.libgraal/src/org/graalvm/compiler/truffle/compiler/hotspot/libgraal/HSTruffleCompilerListener.java index f30d5d68afb6..a61240580a9e 100644 --- a/compiler/src/org.graalvm.compiler.truffle.compiler.hotspot.libgraal/src/org/graalvm/compiler/truffle/compiler/hotspot/libgraal/HSTruffleCompilerListener.java +++ b/compiler/src/org.graalvm.compiler.truffle.compiler.hotspot.libgraal/src/org/graalvm/compiler/truffle/compiler/hotspot/libgraal/HSTruffleCompilerListener.java @@ -39,9 +39,11 @@ import java.io.Closeable; import org.graalvm.compiler.truffle.common.CompilableTruffleAST; +import org.graalvm.compiler.truffle.common.TruffleCompilationTask; import org.graalvm.compiler.truffle.common.TruffleCompilerListener; import org.graalvm.compiler.truffle.common.TruffleInliningData; import org.graalvm.compiler.truffle.common.hotspot.libgraal.TruffleFromLibGraal; +import org.graalvm.compiler.truffle.compiler.TruffleCompilerImpl; import org.graalvm.nativebridge.jni.HSObject; import org.graalvm.nativebridge.jni.JNI.JNIEnv; import org.graalvm.nativebridge.jni.JNI.JObject; @@ -102,10 +104,11 @@ public void onFailure(CompilableTruffleAST compilable, String serializedExceptio @TruffleFromLibGraal(OnCompilationRetry) @Override - public void onCompilationRetry(CompilableTruffleAST compilable, int tier) { + public void onCompilationRetry(CompilableTruffleAST compilable, TruffleCompilationTask task) { JObject hsCompilable = ((HSCompilableTruffleAST) compilable).getHandle(); + JObject hsTask = ((HSTruffleCompilationTask) ((TruffleCompilerImpl.CancellableTruffleCompilationTask) task).getDelegate()).getHandle(); JNIEnv env = JNIMethodScope.env(); - callOnCompilationRetry(env, getHandle(), hsCompilable, tier); + callOnCompilationRetry(env, getHandle(), hsCompilable, hsTask); } private static final class LibGraalObjectHandleScope implements Closeable { diff --git a/compiler/src/org.graalvm.compiler.truffle.compiler/src/org/graalvm/compiler/truffle/compiler/ExpansionStatistics.java b/compiler/src/org.graalvm.compiler.truffle.compiler/src/org/graalvm/compiler/truffle/compiler/ExpansionStatistics.java index f7896f79c9ec..0b082d3f76e8 100644 --- a/compiler/src/org.graalvm.compiler.truffle.compiler/src/org/graalvm/compiler/truffle/compiler/ExpansionStatistics.java +++ b/compiler/src/org.graalvm.compiler.truffle.compiler/src/org/graalvm/compiler/truffle/compiler/ExpansionStatistics.java @@ -294,8 +294,7 @@ private static int orderBySumDesc(Entry e0, Entry e1) { private static TreeNode buildMethodTree(StructuredGraph graph) { TreeNode root = new TreeNode(null, null, ExpansionStatistics::buildMethodTreeLabel); - SchedulePhase schedule = new SchedulePhase(SchedulePhase.SchedulingStrategy.LATEST_OUT_OF_LOOPS, true); - schedule.apply(graph); + SchedulePhase.runWithoutContextOptimizations(graph, SchedulePhase.SchedulingStrategy.LATEST_OUT_OF_LOOPS, true); ControlFlowGraph cfg = graph.getLastSchedule().getCFG(); for (Node node : graph.getNodes()) { NodeSourcePosition nodeSourcePosition = node.getNodeSourcePosition(); diff --git a/compiler/src/org.graalvm.compiler.truffle.compiler/src/org/graalvm/compiler/truffle/compiler/PartialEvaluator.java b/compiler/src/org.graalvm.compiler.truffle.compiler/src/org/graalvm/compiler/truffle/compiler/PartialEvaluator.java index 305730f02adc..f3e588ee394a 100644 --- a/compiler/src/org.graalvm.compiler.truffle.compiler/src/org/graalvm/compiler/truffle/compiler/PartialEvaluator.java +++ b/compiler/src/org.graalvm.compiler.truffle.compiler/src/org/graalvm/compiler/truffle/compiler/PartialEvaluator.java @@ -49,7 +49,6 @@ import org.graalvm.compiler.debug.TimerKey; import org.graalvm.compiler.graph.SourceLanguagePosition; import org.graalvm.compiler.graph.SourceLanguagePositionProvider; -import org.graalvm.compiler.java.ComputeLoopFrequenciesClosure; import org.graalvm.compiler.loop.phases.ConvertDeoptimizeToGuardPhase; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.DeoptimizeNode; @@ -351,8 +350,6 @@ public final StructuredGraph evaluate(Request request) { inliningGraphPE(request); assert GraphOrder.assertSchedulableGraph(request.graph) : "PE result must be schedulable in order to apply subsequent phases"; truffleTier(request); - // recompute loop frequencies now that BranchProbabilities have been canonicalized - ComputeLoopFrequenciesClosure.compute(request.graph); applyInstrumentationPhases(request); handler.reportPerformanceWarnings(request.compilable, request.graph); if (request.task.isCancelled()) { diff --git a/compiler/src/org.graalvm.compiler.truffle.compiler/src/org/graalvm/compiler/truffle/compiler/TruffleCompilerImpl.java b/compiler/src/org.graalvm.compiler.truffle.compiler/src/org/graalvm/compiler/truffle/compiler/TruffleCompilerImpl.java index 0175d6e8ae39..e0a06e084367 100644 --- a/compiler/src/org.graalvm.compiler.truffle.compiler/src/org/graalvm/compiler/truffle/compiler/TruffleCompilerImpl.java +++ b/compiler/src/org.graalvm.compiler.truffle.compiler/src/org/graalvm/compiler/truffle/compiler/TruffleCompilerImpl.java @@ -698,7 +698,7 @@ protected ExceptionAction lookupAction(OptionValues compilerOptions, Throwable c @Override protected DebugContext createRetryDebugContext(DebugContext initialDebug, OptionValues compilerOptions, PrintStream logStream) { - listener.onCompilationRetry(compilable, task.tier()); + listener.onCompilationRetry(compilable, task); return createDebugContext(compilerOptions, compilationId, compilable, logStream); } @@ -947,6 +947,10 @@ public boolean hasNextTier() { public String toString() { return delegate.toString(); } + + public TruffleCompilationTask getDelegate() { + return delegate; + } } private static final class TTYToPolyglotLoggerBridge implements Consumer { diff --git a/compiler/src/org.graalvm.compiler.truffle.compiler/src/org/graalvm/compiler/truffle/compiler/phases/VerifyFrameDoesNotEscapePhase.java b/compiler/src/org.graalvm.compiler.truffle.compiler/src/org/graalvm/compiler/truffle/compiler/phases/VerifyFrameDoesNotEscapePhase.java index da5f43ff99fe..de0d438d3fe8 100644 --- a/compiler/src/org.graalvm.compiler.truffle.compiler/src/org/graalvm/compiler/truffle/compiler/phases/VerifyFrameDoesNotEscapePhase.java +++ b/compiler/src/org.graalvm.compiler.truffle.compiler/src/org/graalvm/compiler/truffle/compiler/phases/VerifyFrameDoesNotEscapePhase.java @@ -24,7 +24,7 @@ */ package org.graalvm.compiler.truffle.compiler.phases; -import org.graalvm.compiler.graph.VerificationError; +import org.graalvm.compiler.graph.GraalGraphError; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.java.MethodCallTargetNode; import org.graalvm.compiler.nodes.util.GraphUtil; @@ -44,7 +44,7 @@ protected void run(StructuredGraph graph) { if (callTarget.invoke() != null) { String properties = callTarget.getDebugProperties().toString(); String arguments = callTarget.arguments().toString(); - Throwable exception = new VerificationError("Frame escapes at: %s#%s\nproperties:%s\narguments: %s", callTarget, callTarget.targetMethod(), properties, arguments); + Throwable exception = new GraalGraphError("Frame escapes at: %s#%s\nproperties:%s\narguments: %s", callTarget, callTarget.targetMethod(), properties, arguments); throw GraphUtil.approxSourceException(callTarget, exception); } } diff --git a/compiler/src/org.graalvm.compiler.truffle.options/src/org/graalvm/compiler/truffle/options/PolyglotCompilerOptions.java b/compiler/src/org.graalvm.compiler.truffle.options/src/org/graalvm/compiler/truffle/options/PolyglotCompilerOptions.java index e949d5f18e31..75b78455b830 100644 --- a/compiler/src/org.graalvm.compiler.truffle.options/src/org/graalvm/compiler/truffle/options/PolyglotCompilerOptions.java +++ b/compiler/src/org.graalvm.compiler.truffle.options/src/org/graalvm/compiler/truffle/options/PolyglotCompilerOptions.java @@ -178,7 +178,7 @@ public ExceptionAction apply(String s) { try { return ExceptionAction.valueOf(s); } catch (IllegalArgumentException e) { - throw new IllegalArgumentException(ExceptionAction.HELP); + throw new IllegalArgumentException(String.format(ExceptionAction.HELP)); } } }); @@ -365,10 +365,10 @@ private String indent(int nameLength) { private static final String EXPANSION_VALUES = "Accepted values are:%n" + " true - Collect data for the default tier 'truffleTier'.%n" + " false - No data will be collected.%n" + - "Or one or multiple tiers separated by comma (e.g. truffleTier,lowTier) :%n" + + "Or one or multiple tiers separated by comma (e.g. truffleTier,lowTier):%n" + " peTier - After partial evaluation without additional phases applied.%n" + " truffleTier - After partial evaluation with additional phases applied.%n" + - " lowTier - After low tier phases were applied.%n"; + " lowTier - After low tier phases were applied."; @Option(help = "Print a tree of all expanded Java methods with statistics after each compilation. " + EXPANSION_VALUES, category = OptionCategory.INTERNAL) public static final OptionKey> TraceMethodExpansion = new OptionKey<>(Collections.emptySet(), COMPILATION_TIERS_TYPE); @@ -498,7 +498,7 @@ private String indent(int nameLength) { "On runtimes which doesn't support it the option has no effect.", category = OptionCategory.EXPERT) public static final OptionKey EncodedGraphCachePurgeDelay = new OptionKey<>(10_000); - + @Option(help = "Forces the frame clearing mechanism to be executed, even if Frame.clear() is not used.", category = OptionCategory.EXPERT) public static final OptionKey ForceFrameLivenessAnalysis = new OptionKey<>(false); diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime.hotspot.libgraal/src/org/graalvm/compiler/truffle/runtime/hotspot/libgraal/LibGraalHotSpotTruffleCompiler.java b/compiler/src/org.graalvm.compiler.truffle.runtime.hotspot.libgraal/src/org/graalvm/compiler/truffle/runtime/hotspot/libgraal/LibGraalHotSpotTruffleCompiler.java index a9b1155a115e..423c0f8ba73a 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime.hotspot.libgraal/src/org/graalvm/compiler/truffle/runtime/hotspot/libgraal/LibGraalHotSpotTruffleCompiler.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime.hotspot.libgraal/src/org/graalvm/compiler/truffle/runtime/hotspot/libgraal/LibGraalHotSpotTruffleCompiler.java @@ -59,6 +59,7 @@ static final class Handle extends LibGraalObject { private final ThreadLocal activeCompilation = new ThreadLocal<>(); private final LibGraalTruffleRuntime runtime; + private volatile Map previousOptions; private long handle(Supplier> optionsSupplier, CompilableTruffleAST compilable, boolean firstInitialization) { return handleImpl(() -> { @@ -92,6 +93,14 @@ private static long handleImpl(Supplier handleSupplier) { @SuppressWarnings("try") @Override public void initialize(Map options, CompilableTruffleAST compilable, boolean firstInitialization) { + /* + * There can only be a single set of options a compiler can be configured with. The first + * Truffle engine of a process typically initializes the compiler which also determines the + * compiler configuration. Any options specified after that will be ignored. So it is safe + * to store the previous options here and reuse later for recreating a disposed isolate if + * needed. + */ + previousOptions = options; // Force installation of the Truffle call boundary methods. // See AbstractHotSpotTruffleRuntime.setDontInlineCallBoundaryMethod // for further details. @@ -144,7 +153,9 @@ public void shutdown() { @SuppressWarnings("try") public void installTruffleCallBoundaryMethod(ResolvedJavaMethod method) { try (LibGraalScope scope = new LibGraalScope(LibGraalScope.DetachAction.DETACH_RUNTIME_AND_RELEASE)) { - TruffleToLibGraalCalls.installTruffleCallBoundaryMethod(getIsolateThread(), handle(optionsEncoder(null), null, false), LibGraal.translate(method)); + Map options = previousOptions; + assert options != null : "truffle compiler was never initialized"; + TruffleToLibGraalCalls.installTruffleCallBoundaryMethod(getIsolateThread(), handle(options, null), LibGraal.translate(method)); } } @@ -152,7 +163,9 @@ public void installTruffleCallBoundaryMethod(ResolvedJavaMethod method) { @SuppressWarnings("try") public void installTruffleReservedOopMethod(ResolvedJavaMethod method) { try (LibGraalScope scope = new LibGraalScope(LibGraalScope.DetachAction.DETACH_RUNTIME_AND_RELEASE)) { - TruffleToLibGraalCalls.installTruffleReservedOopMethod(getIsolateThread(), handle(optionsEncoder(null), null, false), LibGraal.translate(method)); + Map options = previousOptions; + assert options != null : "truffle compiler was never initialized"; + TruffleToLibGraalCalls.installTruffleReservedOopMethod(getIsolateThread(), handle(options, null), LibGraal.translate(method)); } } diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime.hotspot.libgraal/src/org/graalvm/compiler/truffle/runtime/hotspot/libgraal/TruffleFromLibGraalEntryPoints.java b/compiler/src/org.graalvm.compiler.truffle.runtime.hotspot.libgraal/src/org/graalvm/compiler/truffle/runtime/hotspot/libgraal/TruffleFromLibGraalEntryPoints.java index 1793f52afb19..624b75821f95 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime.hotspot.libgraal/src/org/graalvm/compiler/truffle/runtime/hotspot/libgraal/TruffleFromLibGraalEntryPoints.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime.hotspot.libgraal/src/org/graalvm/compiler/truffle/runtime/hotspot/libgraal/TruffleFromLibGraalEntryPoints.java @@ -383,8 +383,8 @@ static void onFailure(Object listener, Object compilable, String reason, boolean } @TruffleFromLibGraal(OnCompilationRetry) - static void onCompilationRetry(Object listener, Object compilable, int tier) { - ((TruffleCompilerListener) listener).onCompilationRetry((CompilableTruffleAST) compilable, tier); + static void onCompilationRetry(Object listener, Object compilable, Object task) { + ((TruffleCompilerListener) listener).onCompilationRetry((CompilableTruffleAST) compilable, (TruffleCompilationTask) task); } @TruffleFromLibGraal(OnGraalTierFinished) diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime.hotspot/src/org/graalvm/compiler/truffle/runtime/hotspot/AbstractHotSpotTruffleRuntime.java b/compiler/src/org.graalvm.compiler.truffle.runtime.hotspot/src/org/graalvm/compiler/truffle/runtime/hotspot/AbstractHotSpotTruffleRuntime.java index ae911adc5ed9..b1756139cc6b 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime.hotspot/src/org/graalvm/compiler/truffle/runtime/hotspot/AbstractHotSpotTruffleRuntime.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime.hotspot/src/org/graalvm/compiler/truffle/runtime/hotspot/AbstractHotSpotTruffleRuntime.java @@ -181,9 +181,9 @@ public AbstractHotSpotTruffleRuntime() { installReservedOopMethods(null); try { - setReservedReference0 = MethodHandles.publicLookup().findVirtual(HotSpotJVMCIRuntime.class, + setReservedReference0 = MethodHandles.lookup().findVirtual(HotSpotJVMCIRuntime.class, "setThreadLocalObject", MethodType.methodType(void.class, int.class, Object.class)); - getReservedReference0 = MethodHandles.publicLookup().findVirtual(HotSpotJVMCIRuntime.class, + getReservedReference0 = MethodHandles.lookup().findVirtual(HotSpotJVMCIRuntime.class, "getThreadLocalObject", MethodType.methodType(Object.class, int.class)); } catch (NoSuchMethodException | IllegalAccessException e) { /* @@ -268,6 +268,17 @@ public void accept(CompilationTask task) { } } + @Override + public boolean isLatestJVMCI() { + if (getJVMCIReservedReference0 == null) { + return false; + } + if (getJVMCIReservedLongOffset0() == -1) { + return false; + } + return true; + } + /* * Used reflectively in CompilerInitializationTest. */ @@ -454,7 +465,6 @@ public boolean bypassedReservedOop(boolean waitForInit) { throw CompilerDirectives.shouldNotReachHere("bypassedReservedOop without field available. default fast thread locals should be used instead."); } - // finish initialization CompilationTask task = initializationTask; if (task != null) { while (waitForInit) { @@ -467,17 +477,46 @@ public boolean bypassedReservedOop(boolean waitForInit) { continue; } } - // compiler init did install the methods + /* + * We were currently initializing. No need to reinstall the code stubs. Just try using + * them again has a very likely-hood of succeeding or if we do not wait for + * inititialization then the caller can use oop accessor methods + * (setJVMCIReservedReference0, getJVMCIReservedReference0) instead. + */ return true; } + if (!truffleCompilerInitialized) { + /* + * If the initialization did not yet complete here, then this means that initializing + * the compiler failed. We can therefore not continue installing the stubs. So we + * re-throw the compiler initialization error or we return false which will likely + * trigger an assertion error in the caller at a later point. + */ if (truffleCompilerInitializationException != null) { throw new AssertionError("Compiler initialization failed cannot continue.", truffleCompilerInitializationException); } return false; } - // otherwise stubs are installed as part of initialization. + + /* + * If we reached this point we are not initializing anymore and the compiler is successfully + * initialized. If bypassedReservedOop was called this also means that we skipped the + * installed code for the JVMCI reserved oop accessor. This can happen if the debugger steps + * over the code and invalidates any installed Java code stub, the HotSpot code cache + * decides to clean up the the stub for the accessor method or this happened due to an + * initialization race condition. In all three cases the best we can do is to try to install + * the stub code again even if this means repeated compilation and installation of this + * method during debug-stepping. Unfortunately there is no known way to detect invalidation + * of HotSpot installed code reliably. + */ installReservedOopMethods((HotSpotTruffleCompiler) truffleCompiler); + + /* + * We have reinstalled the stubs. Returning true indicates that the caller should retry + * calling the stubs or use other available means like the oop accessor methods + * (setJVMCIReservedReference0, getJVMCIReservedReference0). + */ return true; } diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/BackgroundCompileQueue.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/BackgroundCompileQueue.java index 9b0b779df64f..22f4206a1270 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/BackgroundCompileQueue.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/BackgroundCompileQueue.java @@ -193,17 +193,9 @@ private long nextId() { } public int getQueueSize() { - final ExecutorService threadPool = compilationExecutorService; - if (threadPool instanceof ThreadPoolExecutor) { - BlockingQueue queue = ((ThreadPoolExecutor) threadPool).getQueue(); - int count = 0; - for (Runnable runnable : queue) { - CompilationTask.ExecutorServiceWrapper wrapper = (CompilationTask.ExecutorServiceWrapper) runnable; - if (!wrapper.isCancelled() && !wrapper.compileTask.isCancelled()) { - count++; - } - } - return count; + final ThreadPoolExecutor threadPool = compilationExecutorService; + if (threadPool != null) { + return threadPool.getQueue().size(); } else { return 0; } diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/CompilationTask.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/CompilationTask.java index bff7c078f4af..9b315d6ce8d5 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/CompilationTask.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/CompilationTask.java @@ -70,6 +70,10 @@ public void accept(CompilationTask task) { private double lastWeight; private boolean isOSR; + private double lastRate; + private long time; + private int queueChange; + private CompilationTask(BackgroundCompileQueue.Priority priority, WeakReference targetRef, Consumer action, long id) { this.priority = priority; this.targetRef = targetRef; @@ -264,9 +268,10 @@ boolean updateWeight(long currentTime) { return true; } int count = target.getCallAndLoopCount(); - double weight = rate(count, elapsed) * count; + lastRate = rate(count, elapsed); lastTime = currentTime; lastCount = count; + double weight = (1 + lastRate) * lastCount; if (engineData.traversingFirstTierPriority) { lastWeight = weight; } else { @@ -290,8 +295,8 @@ boolean updateWeight(long currentTime) { } private double rate(int count, long elapsed) { - double rawRate = ((double) count - lastCount) / elapsed; - return 1.0 + (Double.isNaN(rawRate) ? 0 : rawRate); + lastRate = ((double) count - lastCount) / elapsed; + return (Double.isNaN(lastRate) ? 0 : lastRate); } public int targetHighestCompiledTier() { @@ -302,6 +307,34 @@ public int targetHighestCompiledTier() { return target.highestCompiledTier(); } + @Override + public long time() { + return time; + } + + @Override + public double weight() { + return lastWeight; + } + + @Override + public double rate() { + return lastRate; + } + + @Override + public int queueChange() { + return queueChange; + } + + void setTime(long time) { + this.time = time; + } + + void setQueueChange(int queueChange) { + this.queueChange = queueChange; + } + /** * Since {@link BackgroundCompileQueue} uses a {@link java.util.concurrent.ThreadPoolExecutor} * to run compilations, and since the executor expects each {@link Callable} (in our case, the diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/FrameWithoutBoxing.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/FrameWithoutBoxing.java index c9338a7d6dbb..5c1f90868564 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/FrameWithoutBoxing.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/FrameWithoutBoxing.java @@ -27,6 +27,7 @@ import java.lang.reflect.Field; import java.util.Arrays; +import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.FrameDescriptor; @@ -93,22 +94,28 @@ private static Unsafe initUnsafe() { } public FrameWithoutBoxing(FrameDescriptor descriptor, Object[] arguments) { - this.descriptor = descriptor; - this.arguments = arguments; - int size = descriptor.getSize(); + final int size = descriptor.getSize(); + final Object[] localsArray; + final long[] primitiveLocalsArray; + final byte[] tagsArray; if (size == 0) { - this.locals = EMPTY_OBJECT_ARRAY; - this.primitiveLocals = EMPTY_LONG_ARRAY; - this.tags = EMPTY_BYTE_ARRAY; + localsArray = EMPTY_OBJECT_ARRAY; + primitiveLocalsArray = EMPTY_LONG_ARRAY; + tagsArray = EMPTY_BYTE_ARRAY; } else { - this.locals = new Object[size]; + localsArray = new Object[size]; Object defaultValue = descriptor.getDefaultValue(); if (defaultValue != null) { - Arrays.fill(locals, defaultValue); + Arrays.fill(localsArray, defaultValue); } - this.primitiveLocals = new long[size]; - this.tags = new byte[size]; + primitiveLocalsArray = new long[size]; + tagsArray = new byte[size]; } + this.descriptor = descriptor; + this.arguments = arguments; + this.locals = localsArray; + this.primitiveLocals = primitiveLocalsArray; + this.tags = tagsArray; } @Override @@ -306,26 +313,50 @@ public FrameDescriptor getFrameDescriptor() { } private void verifySet(int slotIndex, byte tag) { - checkSlotIndex(slotIndex); - getTags()[slotIndex] = tag; + try { + getTags()[slotIndex] = tag; + } catch (ArrayIndexOutOfBoundsException e) { + resizeAndGetTagsOrThrow(slotIndex)[slotIndex] = tag; + } } - private boolean verifyGet(int slotIndex, byte tag) throws FrameSlotTypeException { - checkSlotIndex(slotIndex); - boolean condition = getTags()[slotIndex] == tag; + private boolean verifyGet(int slotIndex, byte expectedTag) throws FrameSlotTypeException { + byte actualTag = getTagChecked(slotIndex); + boolean condition = actualTag == expectedTag; if (!condition) { CompilerDirectives.transferToInterpreterAndInvalidate(); - throw new FrameSlotTypeException(); + throw frameSlotTypeException(); } return condition; } - private void checkSlotIndex(int slotIndex) { - if (CompilerDirectives.inInterpreter() && slotIndex >= getTags().length) { - if (!resize()) { - throw new IllegalArgumentException(String.format("The frame slot '%s' is not known by the frame descriptor.", slotIndex)); + private byte getTagChecked(int slotIndex) { + try { + return getTags()[slotIndex]; + } catch (ArrayIndexOutOfBoundsException e) { + return resizeAndGetTagsOrThrow(slotIndex)[slotIndex]; + } + } + + private static FrameSlotTypeException frameSlotTypeException() throws FrameSlotTypeException { + CompilerAsserts.neverPartOfCompilation(); + throw new FrameSlotTypeException(); + } + + private byte[] resizeAndGetTagsOrThrow(int slotIndex) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + if (resize()) { + byte[] newTags = getTags(); + if (Integer.compareUnsigned(slotIndex, newTags.length) < 0) { + return newTags; } } + throw outOfBoundsException(slotIndex); + } + + private static IllegalArgumentException outOfBoundsException(int slotIndex) { + CompilerAsserts.neverPartOfCompilation(); + throw new IllegalArgumentException("The frame slot '" + slotIndex + "' is not known by the frame descriptor."); } private static long getPrimitiveOffset(int slotIndex) { @@ -335,11 +366,7 @@ private static long getPrimitiveOffset(int slotIndex) { @Override public Object getValue(FrameSlot slot) { int slotIndex = getFrameSlotIndex(slot); - if (CompilerDirectives.inInterpreter() && slotIndex >= getTags().length) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - resize(); - } - byte tag = getTags()[slotIndex]; + byte tag = getTag(slotIndex); boolean condition = (tag == BOOLEAN_TAG); if (condition) { return getBooleanUnsafe(slotIndex, slot, condition); @@ -371,6 +398,7 @@ public Object getValue(FrameSlot slot) { } boolean resize() { + CompilerAsserts.neverPartOfCompilation(); int oldSize = tags.length; int newSize = descriptor.getSize(); if (newSize > oldSize) { @@ -383,51 +411,53 @@ boolean resize() { return false; } - byte getTag(FrameSlot slot) { - int slotIndex = getFrameSlotIndex(slot); - byte[] cachedTags = getTags(); - if (slotIndex < cachedTags.length) { - return cachedTags[slotIndex]; + private byte getTag(int slotIndex) { + try { + return getTags()[slotIndex]; + } catch (ArrayIndexOutOfBoundsException e) { + return resizeAndGetTags()[slotIndex]; } + } + private byte[] resizeAndGetTags() { CompilerDirectives.transferToInterpreterAndInvalidate(); resize(); - return getTags()[slotIndex]; + return getTags(); } @Override public boolean isObject(FrameSlot slot) { - return getTag(slot) == OBJECT_TAG; + return getTag(getFrameSlotIndex(slot)) == OBJECT_TAG; } @Override public boolean isByte(FrameSlot slot) { - return getTag(slot) == BYTE_TAG; + return getTag(getFrameSlotIndex(slot)) == BYTE_TAG; } @Override public boolean isBoolean(FrameSlot slot) { - return getTag(slot) == BOOLEAN_TAG; + return getTag(getFrameSlotIndex(slot)) == BOOLEAN_TAG; } @Override public boolean isInt(FrameSlot slot) { - return getTag(slot) == INT_TAG; + return getTag(getFrameSlotIndex(slot)) == INT_TAG; } @Override public boolean isLong(FrameSlot slot) { - return getTag(slot) == LONG_TAG; + return getTag(getFrameSlotIndex(slot)) == LONG_TAG; } @Override public boolean isFloat(FrameSlot slot) { - return getTag(slot) == FLOAT_TAG; + return getTag(getFrameSlotIndex(slot)) == FLOAT_TAG; } @Override public boolean isDouble(FrameSlot slot) { - return getTag(slot) == DOUBLE_TAG; + return getTag(getFrameSlotIndex(slot)) == DOUBLE_TAG; } @Override diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalFrameInstance.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalFrameInstance.java index 18990eb4c02f..0cd277794331 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalFrameInstance.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalFrameInstance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,31 +86,37 @@ protected Frame getFrameFrom(InspectedFrame inspectedFrame, FrameAccess access) return frame; } + @TruffleBoundary @Override public Frame getFrame(FrameAccess access) { return getFrameFrom(callTargetFrame, access); } + @TruffleBoundary @Override public boolean isVirtualFrame() { return callTargetFrame.isVirtual(FRAME_INDEX); } + @TruffleBoundary @Override public int getCompilationTier() { return ((CompilationState) callTargetFrame.getLocal(OPTIMIZATION_TIER_FRAME_INDEX)).getTier(); } + @TruffleBoundary @Override public boolean isCompilationRoot() { return ((CompilationState) callTargetFrame.getLocal(OPTIMIZATION_TIER_FRAME_INDEX)).isCompilationRoot(); } + @TruffleBoundary @Override public CallTarget getCallTarget() { return (CallTarget) callTargetFrame.getLocal(CALL_TARGET_INDEX); } + @TruffleBoundary @Override public final Node getCallNode() { if (callNodeFrame != null) { diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalOSRFrameInstance.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalOSRFrameInstance.java index 276287b47499..d597132758eb 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalOSRFrameInstance.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalOSRFrameInstance.java @@ -24,7 +24,10 @@ */ package org.graalvm.compiler.truffle.runtime; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.Frame; +import com.oracle.truffle.api.nodes.RootNode; + import jdk.vm.ci.code.stack.InspectedFrame; /** @@ -40,21 +43,33 @@ public final class GraalOSRFrameInstance extends GraalFrameInstance { this.osrFrame = osrFrame; } + @TruffleBoundary @Override public Frame getFrame(FrameAccess access) { - return getFrameFrom(osrFrame, access); + Frame materializedOSRFrame = getFrameFrom(osrFrame, access); + if (getOSRRootNode() instanceof OptimizedOSRLoopNode.LoopOSRRootNode) { + return (Frame) materializedOSRFrame.getArguments()[0]; + } + return materializedOSRFrame; + } + + private RootNode getOSRRootNode() { + return ((OptimizedCallTarget) osrFrame.getLocal(GraalFrameInstance.CALL_TARGET_INDEX)).getRootNode(); } + @TruffleBoundary @Override public boolean isVirtualFrame() { return osrFrame.isVirtual(FRAME_INDEX); } + @TruffleBoundary @Override public int getCompilationTier() { return ((CompilationState) osrFrame.getLocal(OPTIMIZATION_TIER_FRAME_INDEX)).getTier(); } + @TruffleBoundary @Override public boolean isCompilationRoot() { return ((CompilationState) osrFrame.getLocal(OPTIMIZATION_TIER_FRAME_INDEX)).isCompilationRoot(); diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalRuntimeSupport.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalRuntimeSupport.java index 247866ee18d3..5d623842c137 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalRuntimeSupport.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalRuntimeSupport.java @@ -32,6 +32,7 @@ import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.TruffleLogger; import com.oracle.truffle.api.TruffleSafepoint; import com.oracle.truffle.api.frame.Frame; @@ -55,6 +56,14 @@ final class GraalRuntimeSupport extends RuntimeSupport { super(permission); } + @Override + public RootCallTarget newCallTarget(RootNode rootNode) { + CompilerAsserts.neverPartOfCompilation(); + final OptimizedCallTarget target = GraalTruffleRuntime.getRuntime().newCallTarget(rootNode, null); + TruffleSplittingStrategy.newTargetCreated(target); + return target; + } + @ExplodeLoop @Override public void onLoopCount(Node source, int count) { @@ -83,21 +92,7 @@ public boolean pollBytecodeOSRBackEdge(BytecodeOSRNode osrNode) { TruffleSafepoint.poll((Node) osrNode); BytecodeOSRMetadata osrMetadata = (BytecodeOSRMetadata) osrNode.getOSRMetadata(); if (osrMetadata == null) { - Node node = (Node) osrNode; - osrMetadata = node.atomic(() -> { // double checked locking - BytecodeOSRMetadata metadata = (BytecodeOSRMetadata) osrNode.getOSRMetadata(); - if (metadata == null) { - OptimizedCallTarget callTarget = (OptimizedCallTarget) node.getRootNode().getCallTarget(); - if (callTarget.getOptionValue(PolyglotCompilerOptions.OSR)) { - metadata = new BytecodeOSRMetadata(osrNode, callTarget.getOptionValue(PolyglotCompilerOptions.OSRCompilationThreshold)); - } else { - metadata = BytecodeOSRMetadata.DISABLED; - } - - osrNode.setOSRMetadata(metadata); - } - return metadata; - }); + osrMetadata = initializeBytecodeOSRMetadata(osrNode); } // metadata can be set to DISABLED during initialization (above) or dynamically after @@ -109,6 +104,24 @@ public boolean pollBytecodeOSRBackEdge(BytecodeOSRNode osrNode) { } } + private static BytecodeOSRMetadata initializeBytecodeOSRMetadata(BytecodeOSRNode osrNode) { + Node node = (Node) osrNode; + return node.atomic(() -> { // double checked locking + BytecodeOSRMetadata metadata = (BytecodeOSRMetadata) osrNode.getOSRMetadata(); + if (metadata == null) { + OptimizedCallTarget callTarget = (OptimizedCallTarget) node.getRootNode().getCallTarget(); + if (callTarget.getOptionValue(PolyglotCompilerOptions.OSR)) { + metadata = new BytecodeOSRMetadata(osrNode, callTarget.getOptionValue(PolyglotCompilerOptions.OSRCompilationThreshold)); + } else { + metadata = BytecodeOSRMetadata.DISABLED; + } + + osrNode.setOSRMetadata(metadata); + } + return metadata; + }); + } + @Override public Object tryBytecodeOSR(BytecodeOSRNode osrNode, int target, Object interpreterState, Runnable beforeTransfer, VirtualFrame parentFrame) { CompilerAsserts.neverPartOfCompilation(); diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTestTVMCI.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTestTVMCI.java index 2a46c58dc2ea..ae21216aa02c 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTestTVMCI.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTestTVMCI.java @@ -109,7 +109,7 @@ protected GraalTestContext createTestContext(String testName) { @Override public OptimizedCallTarget createTestCallTarget(GraalTestContext testContext, RootNode testNode) { - OptimizedCallTarget target = (OptimizedCallTarget) truffleRuntime.createCallTarget(testNode); + OptimizedCallTarget target = (OptimizedCallTarget) testNode.getCallTarget(); testContext.init(target); return target; } diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntime.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntime.java index 624cae5c5496..521c63c1b563 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntime.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntime.java @@ -186,6 +186,10 @@ public GraalTruffleRuntime(Iterable> extraLookupTypes) { this.floodControlHandler = loadGraalRuntimeServiceProvider(FloodControlHandler.class, null, false); } + public boolean isLatestJVMCI() { + return true; + } + public abstract ThreadLocalHandshake getThreadLocalHandshake(); @Override @@ -691,14 +695,13 @@ public T getCapability(Class capability) { public abstract SpeculationLog createSpeculationLog(); @Override + @Deprecated + @SuppressWarnings("deprecation") public final RootCallTarget createCallTarget(RootNode rootNode) { - CompilerAsserts.neverPartOfCompilation(); - final OptimizedCallTarget target = createClonedCallTarget(rootNode, null); - TruffleSplittingStrategy.newTargetCreated(target); - return target; + return rootNode.getCallTarget(); } - public final OptimizedCallTarget createClonedCallTarget(RootNode rootNode, OptimizedCallTarget source) { + public final OptimizedCallTarget newCallTarget(RootNode rootNode, OptimizedCallTarget source) { CompilerAsserts.neverPartOfCompilation(); OptimizedCallTarget target = createOptimizedCallTarget(source, rootNode); GraalRuntimeAccessor.INSTRUMENT.onLoad(target.getRootNode()); @@ -713,7 +716,7 @@ public final OptimizedCallTarget createClonedCallTarget(RootNode rootNode, Optim public final OptimizedCallTarget createOSRCallTarget(RootNode rootNode) { CompilerAsserts.neverPartOfCompilation(); OptimizedCallTarget target = createOptimizedCallTarget(null, rootNode); - GraalRuntimeAccessor.INSTRUMENT.onLoad(target.getRootNode()); + GraalRuntimeAccessor.INSTRUMENT.onLoad(rootNode); return target; } @@ -778,7 +781,7 @@ private void compileImpl(TruffleDebugContext initialDebug, OptimizedCallTarget c if (debug == null) { debug = compiler.openDebugContext(optionsMap, compilation); } - listeners.onCompilationStarted(callTarget, task.tier()); + listeners.onCompilationStarted(callTarget, task); compilationStarted = true; try { compiler.doCompile(debug, compilation, optionsMap, task, listeners.isEmpty() ? null : listeners); diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntimeListener.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntimeListener.java index 9de24d2bd264..c0671be40338 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntimeListener.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntimeListener.java @@ -26,6 +26,7 @@ import java.util.Map; +import org.graalvm.compiler.truffle.common.TruffleCompilationTask; import org.graalvm.compiler.truffle.common.TruffleCompilerListener.CompilationResultInfo; import org.graalvm.compiler.truffle.common.TruffleCompilerListener.GraphInfo; @@ -112,20 +113,25 @@ default void onCompilationDequeued(OptimizedCallTarget target, Object source, Ch } /** + * @param target the call target about to be compiled + * @param tier Which compilation tier is in question. + * * @deprecated Use {@link #onCompilationStarted(OptimizedCallTarget, int)} */ @Deprecated - default void onCompilationStarted(OptimizedCallTarget target) { - onCompilationStarted(target, 0); + @SuppressWarnings("unused") + default void onCompilationStarted(OptimizedCallTarget target, int tier) { } /** * Notifies this object when compilation of {@code target} is about to start. * * @param target the call target about to be compiled - * @param tier Which compilation tier is in question. + * @param task which compilation task is in question. */ - default void onCompilationStarted(OptimizedCallTarget target, int tier) { + @SuppressWarnings({"unused", "deprecated"}) + default void onCompilationStarted(OptimizedCallTarget target, TruffleCompilationTask task) { + onCompilationStarted(target, task.tier()); } /** diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntimeListenerDispatcher.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntimeListenerDispatcher.java index 17cc552d9c88..6b2295933c72 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntimeListenerDispatcher.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntimeListenerDispatcher.java @@ -28,6 +28,7 @@ import java.util.function.Consumer; import org.graalvm.compiler.truffle.common.CompilableTruffleAST; +import org.graalvm.compiler.truffle.common.TruffleCompilationTask; import org.graalvm.compiler.truffle.common.TruffleCompilerListener; import org.graalvm.compiler.truffle.common.TruffleInliningData; @@ -74,10 +75,16 @@ public void onCompilationFailed(OptimizedCallTarget target, String reason, boole } @Override + @SuppressWarnings("deprecation") public void onCompilationStarted(OptimizedCallTarget target, int tier) { invokeListeners((l) -> l.onCompilationStarted(target, tier)); } + @Override + public void onCompilationStarted(OptimizedCallTarget target, TruffleCompilationTask task) { + invokeListeners((l) -> l.onCompilationStarted(target, task)); + } + @Override public void onCompilationTruffleTierFinished(OptimizedCallTarget target, TruffleInlining inliningDecision, GraphInfo graph) { invokeListeners((l) -> l.onCompilationTruffleTierFinished(target, inliningDecision, graph)); @@ -161,8 +168,8 @@ public void onFailure(CompilableTruffleAST compilable, String reason, boolean ba } @Override - public void onCompilationRetry(CompilableTruffleAST compilable, int tier) { - onCompilationQueued((OptimizedCallTarget) compilable, tier); - onCompilationStarted((OptimizedCallTarget) compilable, tier); + public void onCompilationRetry(CompilableTruffleAST compilable, TruffleCompilationTask task) { + onCompilationQueued((OptimizedCallTarget) compilable, task.tier()); + onCompilationStarted((OptimizedCallTarget) compilable, task); } } diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/OptimizedBlockNode.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/OptimizedBlockNode.java index 723b319415a7..32c8313229fd 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/OptimizedBlockNode.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/OptimizedBlockNode.java @@ -86,11 +86,7 @@ private int profileArg(int arg) { if (a == null) { if (CompilerDirectives.inInterpreter()) { // no need to deoptimize if the block was never executed - if (arg == NO_ARGUMENT) { - alwaysNoArgument = Truffle.getRuntime().createAssumption("Always zero block node argument."); - } else { - alwaysNoArgument = NeverValidAssumption.INSTANCE; - } + alwaysNoArgument = makeAlwaysZeroAssumption(arg == NO_ARGUMENT); } } else if (a.isValid()) { if (arg == NO_ARGUMENT) { @@ -103,6 +99,14 @@ private int profileArg(int arg) { return arg; } + private static Assumption makeAlwaysZeroAssumption(boolean valid) { + if (valid) { + return Truffle.getRuntime().createAssumption("Always zero block node argument."); + } else { + return NeverValidAssumption.INSTANCE; + } + } + @Override @ExplodeLoop public void executeVoid(VirtualFrame frame, int argument) { @@ -320,10 +324,18 @@ private static PartialBlocks computePartialBlocks(OptimizedC if (i > 0) { if (blockRanges == null) { blockRanges = new int[8]; - blockSizes = new int[8]; + /* + * blockSizes array needs one more slot than blockRanges because of the + * assignment below the for-loop. + */ + blockSizes = new int[blockRanges.length + 1]; } else if (currentBlockIndex >= blockRanges.length) { blockRanges = Arrays.copyOf(blockRanges, blockRanges.length * 2); - blockSizes = Arrays.copyOf(blockSizes, blockSizes.length * 2); + /* + * blockSizes array needs one more slot than blockRanges because of the + * assignment below the for-loop. + */ + blockSizes = Arrays.copyOf(blockSizes, blockRanges.length + 1); } blockSizes[currentBlockIndex] = currentBlockSize; blockRanges[currentBlockIndex++] = i; @@ -639,7 +651,7 @@ public static final class PartialBlocks { PartialBlockRootNode partialRootNode = new PartialBlockRootNode<>(new FrameDescriptor(), block, startIndex, endIndex, blockIndex); GraalRuntimeAccessor.NODES.applyPolyglotEngine(rootNode, partialRootNode); - targets[i] = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(partialRootNode); + targets[i] = (OptimizedCallTarget) partialRootNode.getCallTarget(); targets[i].setNonTrivialNodeCount(blockSizes[i]); // we know the parameter types for block compilations. No need to check, lets cast // them unsafely. diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/OptimizedCallTarget.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/OptimizedCallTarget.java index f12f710637a0..fc1a90521c77 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/OptimizedCallTarget.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/OptimizedCallTarget.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.Objects; import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import java.util.function.Supplier; @@ -328,6 +329,8 @@ public Class getType() { private volatile WeakReference singleCallNode = NO_CALL; volatile List blockCompilations; + public final int id; + private static final AtomicInteger idCounter = new AtomicInteger(0); protected OptimizedCallTarget(OptimizedCallTarget sourceCallTarget, RootNode rootNode) { assert sourceCallTarget == null || sourceCallTarget.sourceCallTarget == null : "Cannot create a clone of a cloned CallTarget"; @@ -339,7 +342,7 @@ protected OptimizedCallTarget(OptimizedCallTarget sourceCallTarget, RootNode roo // Do not adopt children of OSRRootNodes; we want to preserve the parent of the child // node(s). this.uninitializedNodeCount = !isOSR() ? GraalRuntimeAccessor.NODES.adoptChildrenAndCount(rootNode) : -1; - GraalRuntimeAccessor.NODES.setCallTarget(rootNode, this); + id = idCounter.getAndIncrement(); } final Assumption getNodeRewritingAssumption() { @@ -840,7 +843,7 @@ final OptimizedCallTarget cloneUninitialized() { } else { clonedRoot = NodeUtil.cloneNode(uninitializedRootNode); } - return runtime().createClonedCallTarget(clonedRoot, this); + return runtime().newCallTarget(clonedRoot, this); } /** @@ -994,7 +997,7 @@ public final String getName() { if (result == null) { result = rootNode.toString(); if (sourceCallTarget != null) { - result += " "; + result += " "; } nameCache = result; } diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/OptimizedOSRLoopNode.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/OptimizedOSRLoopNode.java index d64dd580dab7..66561b8a20b8 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/OptimizedOSRLoopNode.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/OptimizedOSRLoopNode.java @@ -83,7 +83,7 @@ private OptimizedOSRLoopNode(RepeatingNode repeatingNode, int osrThreshold, bool /** * @param rootFrameDescriptor may be {@code null}. */ - protected LoopOSRRootNode createRootNode(FrameDescriptor rootFrameDescriptor, Class clazz) { + protected AbstractLoopOSRRootNode createRootNode(FrameDescriptor rootFrameDescriptor, Class clazz) { /* * Use a new frame descriptor, because the frame that this new root node creates is not * used. @@ -100,10 +100,11 @@ public final Node copy() { @Override public Object execute(VirtualFrame frame) { + RepeatingNode loopBody = repeatingNode; if (CompilerDirectives.inInterpreter()) { try { - Object status = repeatingNode.initialLoopStatus(); - while (repeatingNode.shouldContinue(status)) { + Object status = loopBody.initialLoopStatus(); + while (loopBody.shouldContinue(status)) { if (compiledOSRLoop == null) { status = profilingLoop(frame); } else { @@ -118,7 +119,7 @@ public Object execute(VirtualFrame frame) { long iterationsCompleted = 0; Object status; try { - while (inject(repeatingNode.shouldContinue((status = repeatingNode.executeRepeatingWithValue(frame))))) { + while (inject(loopBody.shouldContinue((status = loopBody.executeRepeatingWithValue(frame))))) { iterationsCompleted++; if (CompilerDirectives.inInterpreter()) { // compiled method got invalidated. We might need OSR again. @@ -134,7 +135,7 @@ public Object execute(VirtualFrame frame) { return status; } else { Object status; - while (inject(repeatingNode.shouldContinue((status = repeatingNode.executeRepeatingWithValue(frame))))) { + while (inject(loopBody.shouldContinue((status = loopBody.executeRepeatingWithValue(frame))))) { if (CompilerDirectives.inInterpreter()) { // compiled method got invalidated. We might need OSR again. return execute(frame); @@ -150,10 +151,11 @@ static int toIntOrMaxInt(long i) { } private Object profilingLoop(VirtualFrame frame) { + RepeatingNode loopBody = repeatingNode; long iterations = 0; try { Object status; - while (repeatingNode.shouldContinue(status = repeatingNode.executeRepeatingWithValue(frame))) { + while (loopBody.shouldContinue(status = loopBody.executeRepeatingWithValue(frame))) { // the baseLoopCount might be updated from a child loop during an iteration. if (++iterations + baseLoopCount > osrThreshold && !compilationDisabled) { compileLoop(frame); @@ -176,10 +178,11 @@ private void reportLoopIterations(long iterations) { } final void reportChildLoopCount(int iterations) { - baseLoopCount += iterations; - if (baseLoopCount < 0) { - baseLoopCount = Integer.MAX_VALUE; + int newBaseLoopCount = baseLoopCount + iterations; + if (newBaseLoopCount < 0) { // overflowed + newBaseLoopCount = Integer.MAX_VALUE; } + baseLoopCount = newBaseLoopCount; } /** @@ -197,24 +200,25 @@ public final OptimizedCallTarget getCompiledOSRLoop() { } private Object compilingLoop(VirtualFrame frame) { + RepeatingNode loopBody = repeatingNode; long iterations = 0; try { Object status; do { OptimizedCallTarget target = compiledOSRLoop; if (target == null) { - return repeatingNode.initialLoopStatus(); + return loopBody.initialLoopStatus(); } if (!target.isSubmittedForCompilation()) { if (target.isValid()) { return callOSR(target, frame); } invalidateOSRTarget("OSR compilation failed or cancelled"); - return repeatingNode.initialLoopStatus(); + return loopBody.initialLoopStatus(); } iterations++; TruffleSafepoint.poll(this); - } while (repeatingNode.shouldContinue(status = repeatingNode.executeRepeatingWithValue(frame))); + } while (loopBody.shouldContinue(status = loopBody.executeRepeatingWithValue(frame))); return status; } finally { reportLoopIterations(iterations); @@ -252,7 +256,7 @@ public void run() { }); } - private LoopOSRRootNode createRootNodeImpl(RootNode root, Class frameClass) { + private AbstractLoopOSRRootNode createRootNodeImpl(RootNode root, Class frameClass) { return createRootNode(root == null ? null : root.getFrameDescriptor(), frameClass); } @@ -415,7 +419,7 @@ private OptimizedVirtualizingOSRLoopNode(RepeatingNode repeatableNode, int osrTh } @Override - protected LoopOSRRootNode createRootNode(FrameDescriptor rootFrameDescriptor, Class clazz) { + protected AbstractLoopOSRRootNode createRootNode(FrameDescriptor rootFrameDescriptor, Class clazz) { if (readFrameSlots == null || writtenFrameSlots == null) { return super.createRootNode(rootFrameDescriptor, clazz); } else { @@ -433,7 +437,7 @@ protected LoopOSRRootNode createRootNode(FrameDescriptor rootFrameDescriptor, Cl } - public static class LoopOSRRootNode extends BaseOSRRootNode { + abstract static class AbstractLoopOSRRootNode extends BaseOSRRootNode { protected final Class clazz; @@ -443,7 +447,7 @@ public static class LoopOSRRootNode extends BaseOSRRootNode { */ @Child protected OptimizedOSRLoopNode loopNode; - LoopOSRRootNode(OptimizedOSRLoopNode loop, FrameDescriptor frameDescriptor, Class clazz) { + AbstractLoopOSRRootNode(OptimizedOSRLoopNode loop, FrameDescriptor frameDescriptor, Class clazz) { super(null, frameDescriptor); this.loopNode = loop; this.clazz = clazz; @@ -457,10 +461,11 @@ public SourceSection getSourceSection() { @Override protected Object executeOSR(VirtualFrame frame) { VirtualFrame parentFrame = clazz.cast(frame.getArguments()[0]); + RepeatingNode loopBody = loopNode.repeatingNode; Object status; - while (loopNode.repeatingNode.shouldContinue(status = loopNode.getRepeatingNode().executeRepeatingWithValue(parentFrame))) { + while (loopBody.shouldContinue(status = loopBody.executeRepeatingWithValue(parentFrame))) { if (CompilerDirectives.inInterpreter()) { - return loopNode.repeatingNode.initialLoopStatus(); + return loopBody.initialLoopStatus(); } TruffleSafepoint.poll(this); } @@ -478,7 +483,13 @@ public final String toString() { } } - private static final class VirtualizingLoopOSRRootNode extends LoopOSRRootNode { + static final class LoopOSRRootNode extends AbstractLoopOSRRootNode { + LoopOSRRootNode(OptimizedOSRLoopNode loop, FrameDescriptor frameDescriptor, Class clazz) { + super(loop, frameDescriptor, clazz); + } + } + + private static final class VirtualizingLoopOSRRootNode extends AbstractLoopOSRRootNode { @CompilationFinal(dimensions = 1) private final FrameSlot[] readFrameSlots; @CompilationFinal(dimensions = 1) private final FrameSlot[] writtenFrameSlots; @@ -534,10 +545,11 @@ protected Object executeOSR(VirtualFrame originalFrame) { FrameWithoutBoxing parentFrame = (FrameWithoutBoxing) (loopFrame.getArguments()[0]); executeTransfer(parentFrame, loopFrame, readFrameSlots, readFrameSlotsTags); try { + RepeatingNode loopBody = loopNode.repeatingNode; Object status; - while (loopNode.repeatingNode.shouldContinue(status = loopNode.getRepeatingNode().executeRepeatingWithValue(loopFrame))) { + while (loopBody.shouldContinue(status = loopBody.executeRepeatingWithValue(loopFrame))) { if (CompilerDirectives.inInterpreter()) { - return loopNode.repeatingNode.initialLoopStatus(); + return loopBody.initialLoopStatus(); } TruffleSafepoint.poll(this); } diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/TraversingBlockingQueue.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/TraversingBlockingQueue.java index 6d29f5870772..58bc083ae0c8 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/TraversingBlockingQueue.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/TraversingBlockingQueue.java @@ -79,23 +79,33 @@ private synchronized Runnable takeMax() { if (entries.isEmpty()) { return null; } - long time = System.nanoTime(); - Iterator it = entries.iterator(); Runnable max = null; - while (it.hasNext()) { - Runnable entry = it.next(); - CompilationTask task = task(entry); - // updateWeight returns false only if the task's target does not exist - if (task.isCancelled() || !task.updateWeight(time)) { - it.remove(); - continue; + long time = System.nanoTime(); + int removed = 0; + try { + Iterator it = entries.iterator(); + while (it.hasNext()) { + Runnable entry = it.next(); + CompilationTask task = task(entry); + // updateWeight returns false only if the task's target does not exist + if (task.isCancelled() || !task.updateWeight(time)) { + it.remove(); + removed--; + continue; + } + if (max == null || task.isHigherPriorityThan(task(max))) { + max = entry; + } } - if (max == null || task.isHigherPriorityThan(task(max))) { - max = entry; + // entries.remove can only return false if a sleeping thread takes the only element + return entries.remove(max) ? max : null; + } finally { + if (max != null) { + CompilationTask task = task(max); + task.setTime(System.nanoTime() - time); + task.setQueueChange(removed - 1); } } - // entries.remove can only return false if a sleeping thread takes the only element - return entries.remove(max) ? max : null; } @Override diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/TruffleSplittingStrategy.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/TruffleSplittingStrategy.java index 2c8f3d5465e3..778fa7ee718a 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/TruffleSplittingStrategy.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/TruffleSplittingStrategy.java @@ -52,31 +52,43 @@ final class TruffleSplittingStrategy { static void beforeCall(OptimizedDirectCallNode call, OptimizedCallTarget currentTarget) { final EngineData engineData = currentTarget.engine; if (engineData.traceSplittingSummary) { - if (currentTarget.getCallCount() == 0) { - synchronized (engineData.splittingStatistics) { - engineData.splittingStatistics.totalExecutedNodeCount += currentTarget.getUninitializedNodeCount(); - } - } + traceSplittingPreShouldSplit(engineData, currentTarget); } if (shouldSplit(engineData, call)) { - engineData.splitCount += call.getCallTarget().getUninitializedNodeCount(); doSplit(engineData, call); } } - private static void doSplit(EngineData engineData, OptimizedDirectCallNode call) { - if (engineData.traceSplittingSummary) { + private static void traceSplittingPreShouldSplit(final EngineData engineData, OptimizedCallTarget currentTarget) { + if (currentTarget.getCallCount() == 0) { synchronized (engineData.splittingStatistics) { - calculateSplitWasteImpl(call.getCurrentCallTarget()); + engineData.splittingStatistics.totalExecutedNodeCount += currentTarget.getUninitializedNodeCount(); } } + } + + private static void doSplit(EngineData engineData, OptimizedDirectCallNode call) { + engineData.splitCount += call.getCallTarget().getUninitializedNodeCount(); + if (engineData.traceSplittingSummary) { + traceSplittingPreSplit(engineData, call); + } call.split(); if (engineData.traceSplittingSummary) { - synchronized (engineData.splittingStatistics) { - engineData.splittingStatistics.splitNodeCount += call.getCurrentCallTarget().getUninitializedNodeCount(); - engineData.splittingStatistics.splitCount++; - engineData.splittingStatistics.splitTargets.put(call.getCallTarget(), engineData.splittingStatistics.splitTargets.getOrDefault(call.getCallTarget(), 0) + 1); - } + traceSplittingPostSplit(engineData, call); + } + } + + private static void traceSplittingPreSplit(EngineData engineData, OptimizedDirectCallNode call) { + synchronized (engineData.splittingStatistics) { + calculateSplitWasteImpl(call.getCurrentCallTarget()); + } + } + + private static void traceSplittingPostSplit(EngineData engineData, OptimizedDirectCallNode call) { + synchronized (engineData.splittingStatistics) { + engineData.splittingStatistics.splitNodeCount += call.getCurrentCallTarget().getUninitializedNodeCount(); + engineData.splittingStatistics.splitCount++; + engineData.splittingStatistics.splitTargets.put(call.getCallTarget(), engineData.splittingStatistics.splitTargets.getOrDefault(call.getCallTarget(), 0) + 1); } } @@ -137,13 +149,17 @@ static void forceSplitting(OptimizedDirectCallNode call) { engineData.splitCount += call.getCurrentCallTarget().getUninitializedNodeCount(); doSplit(engineData, call); if (engineData.traceSplittingSummary) { - synchronized (engineData.splittingStatistics) { - engineData.splittingStatistics.forcedSplitCount++; - } + traceSplittingForcedSplit(engineData); } } } + private static void traceSplittingForcedSplit(final EngineData engineData) { + synchronized (engineData.splittingStatistics) { + engineData.splittingStatistics.forcedSplitCount++; + } + } + private static boolean canSplit(EngineData engine, OptimizedDirectCallNode call) { if (call.isCallTargetCloned()) { return false; @@ -200,9 +216,13 @@ static void newTargetCreated(RootCallTarget target) { engineData.splitLimit = (int) (engineData.splitLimit + engineData.splittingGrowthLimit * callTarget.getUninitializedNodeCount()); } if (engineData.traceSplittingSummary) { - synchronized (engineData.splittingStatistics) { - engineData.splittingStatistics.totalCreatedNodeCount += callTarget.getUninitializedNodeCount(); - } + traceSplittingNewCallTarget(callTarget, engineData); + } + } + + private static void traceSplittingNewCallTarget(OptimizedCallTarget callTarget, EngineData engineData) { + synchronized (engineData.splittingStatistics) { + engineData.splittingStatistics.totalCreatedNodeCount += callTarget.getUninitializedNodeCount(); } } @@ -222,11 +242,15 @@ private static void calculateSplitWasteImpl(OptimizedCallTarget callTarget) { static void newPolymorphicSpecialize(Node node, EngineData engineData) { if (engineData.traceSplittingSummary) { - synchronized (engineData.splittingStatistics) { - final Map, Integer> polymorphicNodes = engineData.splittingStatistics.polymorphicNodes; - final Class aClass = node.getClass(); - polymorphicNodes.put(aClass, polymorphicNodes.getOrDefault(aClass, 0) + 1); - } + traceSplittingNewPolymorphicSpecialize(node, engineData); + } + } + + private static void traceSplittingNewPolymorphicSpecialize(Node node, EngineData engineData) { + synchronized (engineData.splittingStatistics) { + final Map, Integer> polymorphicNodes = engineData.splittingStatistics.polymorphicNodes; + final Class aClass = node.getClass(); + polymorphicNodes.put(aClass, polymorphicNodes.getOrDefault(aClass, 0) + 1); } } diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/debug/JFRListener.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/debug/JFRListener.java index 950b6195efd8..8b59a10e1b81 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/debug/JFRListener.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/debug/JFRListener.java @@ -27,6 +27,7 @@ import java.util.Iterator; import java.util.concurrent.atomic.AtomicLong; +import org.graalvm.compiler.truffle.common.TruffleCompilationTask; import org.graalvm.compiler.truffle.common.TruffleCompilerListener.CompilationResultInfo; import org.graalvm.compiler.truffle.common.TruffleCompilerListener.GraphInfo; import org.graalvm.compiler.truffle.jfr.CompilationEvent; @@ -104,7 +105,7 @@ public static boolean isInstrumented(ResolvedJavaMethod method) { } @Override - public void onCompilationStarted(OptimizedCallTarget target, int tier) { + public void onCompilationStarted(OptimizedCallTarget target, TruffleCompilationTask task) { CompilationEvent event = null; if (factory != null) { event = factory.createCompilationEvent(); diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/debug/StatisticsListener.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/debug/StatisticsListener.java index bd20d827d5e9..945df1805c77 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/debug/StatisticsListener.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/debug/StatisticsListener.java @@ -38,8 +38,8 @@ import java.util.function.Function; import java.util.logging.Level; -import com.oracle.truffle.api.nodes.NodeVisitor; import org.graalvm.compiler.truffle.common.CompilableTruffleAST; +import org.graalvm.compiler.truffle.common.TruffleCompilationTask; import org.graalvm.compiler.truffle.common.TruffleCompilerListener.CompilationResultInfo; import org.graalvm.compiler.truffle.common.TruffleCompilerListener.GraphInfo; import org.graalvm.compiler.truffle.runtime.AbstractGraalTruffleRuntimeListener; @@ -55,6 +55,7 @@ import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeCost; +import com.oracle.truffle.api.nodes.NodeVisitor; public final class StatisticsListener extends AbstractGraalTruffleRuntimeListener { @@ -167,7 +168,7 @@ public synchronized void onCompilationInvalidated(OptimizedCallTarget target, Ob } @Override - public synchronized void onCompilationStarted(OptimizedCallTarget target, int tier) { + public void onCompilationStarted(OptimizedCallTarget target, TruffleCompilationTask task) { compilations++; final Times times = new Times(); compilationTimes.set(times); @@ -620,10 +621,10 @@ public void onCompilationQueued(OptimizedCallTarget target, int tier) { } @Override - public void onCompilationStarted(OptimizedCallTarget target, int tier) { + public void onCompilationStarted(OptimizedCallTarget target, TruffleCompilationTask task) { StatisticsListener listener = target.engine.statisticsListener; if (listener != null) { - listener.onCompilationStarted(target, tier); + listener.onCompilationStarted(target, task); } } diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/debug/TraceCompilationListener.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/debug/TraceCompilationListener.java index af174b538f64..e030f2ee385d 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/debug/TraceCompilationListener.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/debug/TraceCompilationListener.java @@ -24,9 +24,7 @@ */ package org.graalvm.compiler.truffle.runtime.debug; -import java.util.LinkedHashMap; -import java.util.Map; - +import org.graalvm.compiler.truffle.common.TruffleCompilationTask; import org.graalvm.compiler.truffle.common.TruffleCompilerListener.CompilationResultInfo; import org.graalvm.compiler.truffle.common.TruffleCompilerListener.GraphInfo; import org.graalvm.compiler.truffle.runtime.AbstractGraalTruffleRuntimeListener; @@ -49,7 +47,6 @@ public final class TraceCompilationListener extends AbstractGraalTruffleRuntimeListener { private final ThreadLocal currentCompilation = new ThreadLocal<>(); - private long startTime = System.nanoTime(); private TraceCompilationListener(GraalTruffleRuntime runtime) { super(runtime); @@ -59,63 +56,98 @@ public static void install(GraalTruffleRuntime runtime) { runtime.addListener(new TraceCompilationListener(runtime)); } - private static Map defaultProperties(OptimizedCallTarget target) { - Map properties = new LinkedHashMap<>(); - properties.putAll(target.getDebugProperties()); - properties.put("Src", formatSourceSection(target.getRootNode().getSourceSection())); - return properties; - } + public static final String TIER_FORMAT = "Tier %d"; + private static final String QUEUE_FORMAT = "Queue: Size %4d Change %c%-2d Load %5.2f Time %5dus"; + private static final String TARGET_FORMAT = "id=%-5d %-50s "; + public static final String COUNT_THRESHOLD_FORMAT = "Count/Thres %9d/%9d"; + // @formatter:off + private static final String QUEUED_FORMAT = "opt queued " + TARGET_FORMAT + "|" + TIER_FORMAT + "|" + COUNT_THRESHOLD_FORMAT + "|" + QUEUE_FORMAT + "|Timestamp %d|Src %s"; + private static final String UNQUEUED_FORMAT = "opt unque. " + TARGET_FORMAT + "|" + TIER_FORMAT + "|" + COUNT_THRESHOLD_FORMAT + "|" + QUEUE_FORMAT + "|Timestamp %d|Src %s|Reason %s"; + private static final String START_FORMAT = "opt start " + TARGET_FORMAT + "|" + TIER_FORMAT + "|Priority %9d|Rate %.6f|" + QUEUE_FORMAT + "|Timestamp %d|Src %s"; + private static final String DONE_FORMAT = "opt done " + TARGET_FORMAT + "|" + TIER_FORMAT + "|Time %18s|AST %4d|Inlined %3dY %3dN|IR %6d/%6d|CodeSize %7d|Timestamp %d|Src %s"; + private static final String FAILED_FORMAT = "opt failed " + TARGET_FORMAT + "|" + TIER_FORMAT + "|Time %18s|Reason: %s|Timestamp %d|Src %s"; + private static final String INV_FORMAT = "opt inval. " + TARGET_FORMAT + " |Timestamp %d|Src %s|Reason %s"; + private static final String DEOPT_FORMAT = "opt deopt " + TARGET_FORMAT + " |Timestamp %d|Src %s"; + // @formatter:on @Override public void onCompilationQueued(OptimizedCallTarget target, int tier) { if (target.engine.traceCompilationDetails) { - runtime.logEvent(target, 0, "opt queued", queueProperties(target, tier)); + int callAndLoopThreshold = tier == 1 ? target.engine.callAndLoopThresholdInInterpreter : target.engine.callAndLoopThresholdInFirstTier; + int scale = runtime.compilationThresholdScale(); + log(target, String.format(QUEUED_FORMAT, + target.id, + target.getName(), + tier, + target.getCallAndLoopCount(), + FixedPointMath.multiply(scale, callAndLoopThreshold), + runtime.getCompilationQueueSize(), + '+', + 1, + FixedPointMath.toDouble(scale), + 0, + System.nanoTime(), + formatSourceSection(target.getRootNode().getSourceSection()))); } } @Override public void onCompilationDequeued(OptimizedCallTarget target, Object source, CharSequence reason, int tier) { if (target.engine.traceCompilationDetails) { - Map properties = queueProperties(target, tier); - properties.put("Reason", reason); - runtime.logEvent(target, 0, "opt unqueued", properties); + int callAndLoopThreshold = tier == 1 ? target.engine.callAndLoopThresholdInInterpreter : target.engine.callAndLoopThresholdInFirstTier; + int scale = runtime.compilationThresholdScale(); + log(target, String.format(UNQUEUED_FORMAT, + target.id, + target.getName(), + tier, + target.getCallAndLoopCount(), + FixedPointMath.multiply(scale, callAndLoopThreshold), + runtime.getCompilationQueueSize(), + ' ', + 0, + FixedPointMath.toDouble(scale), + 0, + System.nanoTime(), + formatSourceSection(target.getRootNode().getSourceSection()), + reason)); } } - private Map queueProperties(OptimizedCallTarget target, int tier) { - Map properties = new LinkedHashMap<>(); - GraalTruffleRuntimeListener.addASTSizeProperty(target, properties); - properties.put("Tier", Integer.toString(tier)); // to avoid padding - int callThreshold = tier == 1 ? target.engine.callThresholdInInterpreter : target.engine.callThresholdInFirstTier; - int scale = runtime.compilationThresholdScale(); - properties.put("Calls/Thres", String.format("%7d/%5d", target.getCallCount(), FixedPointMath.multiply(scale, callThreshold))); - int callAndLoopThreshold = tier == 1 ? target.engine.callAndLoopThresholdInInterpreter : target.engine.callAndLoopThresholdInFirstTier; - properties.put("CallsAndLoop/Thres", String.format("%7d/%5d", target.getCallAndLoopCount(), FixedPointMath.multiply(scale, callAndLoopThreshold))); - properties.put("Src", formatSourceSection(target.getRootNode().getSourceSection())); - properties.put("QueueSize", runtime.getCompilationQueueSize()); - properties.put("Time", System.nanoTime() - startTime); - properties.put("Scale", FixedPointMath.toDouble(scale)); - return properties; - } - @Override public void onCompilationFailed(OptimizedCallTarget target, String reason, boolean bailout, boolean permanentBailout, int tier) { if (target.engine.traceCompilation || target.engine.traceCompilationDetails) { if (!isPermanentFailure(bailout, permanentBailout)) { onCompilationDequeued(target, null, "Non permanent bailout: " + reason, tier); } else { - Map properties = compilationEndProperties(target, null, null, null, tier); - properties.put("Reason", reason); - runtime.logEvent(target, 0, "opt failed", properties); + log(target, String.format(FAILED_FORMAT, + target.id, + target.getName(), + tier, + compilationTime(), + reason, + System.nanoTime(), + formatSourceSection(target.getRootNode().getSourceSection()))); } currentCompilation.set(null); } } @Override - public void onCompilationStarted(OptimizedCallTarget target, int tier) { + public void onCompilationStarted(OptimizedCallTarget target, TruffleCompilationTask task) { if (target.engine.traceCompilationDetails) { - runtime.logEvent(target, 0, "opt start", queueProperties(target, tier)); + log(target, String.format(START_FORMAT, + target.id, + target.getName(), + task.tier(), + (int) task.weight(), + task.rate(), + runtime.getCompilationQueueSize(), + task.queueChange() >= 0 ? '+' : '-', + Math.abs(task.queueChange()), + FixedPointMath.toDouble(runtime.compilationThresholdScale()), + task.time() / 1000, + System.nanoTime(), + formatSourceSection(target.getRootNode().getSourceSection()))); } if (target.engine.traceCompilation || target.engine.traceCompilationDetails) { @@ -123,13 +155,18 @@ public void onCompilationStarted(OptimizedCallTarget target, int tier) { } } + private void log(OptimizedCallTarget target, String message) { + runtime.log(target, message); + } + @Override public void onCompilationDeoptimized(OptimizedCallTarget target, Frame frame) { if (target.engine.traceCompilation || target.engine.traceCompilationDetails) { - Map properties = new LinkedHashMap<>(); - GraalTruffleRuntimeListener.addASTSizeProperty(target, properties); - properties.put("Src", formatSourceSection(target.getRootNode().getSourceSection())); - runtime.logEvent(target, 0, "opt deopt", properties); + log(target, String.format(DEOPT_FORMAT, + target.id, + target.getName(), + System.nanoTime(), + formatSourceSection(target.getRootNode().getSourceSection()))); } } @@ -147,19 +184,25 @@ public void onCompilationSuccess(OptimizedCallTarget target, TruffleInlining inl if (!target.engine.traceCompilation && !target.engine.traceCompilationDetails) { return; } - - Map properties = compilationEndProperties(target, inliningDecision, graph, result, tier); - - runtime.logEvent(target, 0, "opt done", properties); - + int[] inlinedAndDispatched = inlinedAndDispatched(target, inliningDecision); + Times compilation = currentCompilation.get(); + log(target, String.format(DONE_FORMAT, + target.id, + target.getName(), + tier, + compilationTime(), + target.getNonTrivialNodeCount(), + inlinedAndDispatched[0], + inlinedAndDispatched[1], + compilation.nodeCountPartialEval, + graph == null ? 0 : graph.getNodeCount(), + result == null ? 0 : result.getTargetCodeSize(), + System.nanoTime(), + formatSourceSection(target.getRootNode().getSourceSection()))); currentCompilation.set(null); } - private Map compilationEndProperties(OptimizedCallTarget target, TruffleInlining inliningDecision, GraphInfo graph, CompilationResultInfo result, int tier) { - long timeCompilationFinished = System.nanoTime(); - int nodeCountLowered = graph == null ? 0 : graph.getNodeCount(); - Times compilation = currentCompilation.get(); - + private static int[] inlinedAndDispatched(OptimizedCallTarget target, TruffleInlining inliningDecision) { int calls = 0; int inlinedCalls; if (inliningDecision == null) { @@ -171,25 +214,20 @@ private Map compilationEndProperties(OptimizedCallTarget target, calls = inliningDecision.countCalls(); inlinedCalls = inliningDecision.countInlinedCalls(); } - int dispatchedCalls = calls - inlinedCalls; - Map properties = new LinkedHashMap<>(); - GraalTruffleRuntimeListener.addASTSizeProperty(target, properties); - properties.put("Tier", Integer.toString(tier)); // to avoid padding - properties.put("Time", String.format("%4.0f(%4.0f+%-4.0f)ms", // + int[] inlinedAndDispatched = new int[2]; + inlinedAndDispatched[0] = inlinedCalls; + inlinedAndDispatched[1] = dispatchedCalls; + return inlinedAndDispatched; + } + + private String compilationTime() { + long timeCompilationFinished = System.nanoTime(); + Times compilation = currentCompilation.get(); + return String.format("%4.0f(%4.0f+%-4.0f)ms", // (timeCompilationFinished - compilation.timeCompilationStarted) / 1e6, // (compilation.timePartialEvaluationFinished - compilation.timeCompilationStarted) / 1e6, // - (timeCompilationFinished - compilation.timePartialEvaluationFinished) / 1e6)); - properties.put("Inlined", String.format("%3dY %3dN", inlinedCalls, dispatchedCalls)); - properties.put("IR", String.format("%5d/%5d", compilation.nodeCountPartialEval, nodeCountLowered)); - properties.put("CodeSize", result == null ? 0 : result.getTargetCodeSize()); - if (target.getCodeAddress() != 0) { - properties.put("Addr", "0x" + Long.toHexString(target.getCodeAddress())); - } else { - properties.put("Addr", "N/A"); - } - properties.put("Src", formatSourceSection(target.getRootNode().getSourceSection())); - return properties; + (timeCompilationFinished - compilation.timePartialEvaluationFinished) / 1e6); } private static String formatSourceSection(SourceSection sourceSection) { @@ -202,9 +240,12 @@ private static String formatSourceSection(SourceSection sourceSection) { @Override public void onCompilationInvalidated(OptimizedCallTarget target, Object source, CharSequence reason) { if (target.engine.traceCompilation || target.engine.traceCompilationDetails) { - Map properties = defaultProperties(target); - properties.put("Reason", reason); - runtime.logEvent(target, 0, "opt inv.", properties); + log(target, String.format(INV_FORMAT, + target.id, + target.getName(), + System.nanoTime(), + formatSourceSection(target.getRootNode().getSourceSection()), + reason)); } } diff --git a/compiler/src/org.graalvm.compiler.truffle.test.jdk11/src/org/graalvm/compiler/truffle/test/jdk11/VarHandlePartialEvaluationTest.java b/compiler/src/org.graalvm.compiler.truffle.test.jdk11/src/org/graalvm/compiler/truffle/test/jdk11/VarHandlePartialEvaluationTest.java index b3ae1ded3fae..037c1cf474f9 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test.jdk11/src/org/graalvm/compiler/truffle/test/jdk11/VarHandlePartialEvaluationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test.jdk11/src/org/graalvm/compiler/truffle/test/jdk11/VarHandlePartialEvaluationTest.java @@ -38,7 +38,6 @@ import org.junit.Test; import com.oracle.truffle.api.RootCallTarget; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.RootNode; @@ -89,7 +88,7 @@ public void byteBufferHandleSet() { private void testCommon(AbstractTestNode testNode, String testName, Object... args) { FrameDescriptor fd = new FrameDescriptor(); RootNode rootNode = new RootTestNode(fd, testName, testNode); - RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode); + RootCallTarget callTarget = rootNode.getCallTarget(); Assert.assertEquals(42, callTarget.call(args)); assertPartialEvalNoInvokes(callTarget, args); } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AOTSupportCompilationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AOTSupportCompilationTest.java index fe8a66b95fff..0ece769184e5 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AOTSupportCompilationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AOTSupportCompilationTest.java @@ -26,7 +26,6 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.java.MethodCallTargetNode; -import org.graalvm.compiler.truffle.runtime.GraalTruffleRuntime; import org.graalvm.compiler.truffle.runtime.OptimizedCallTarget; import org.graalvm.polyglot.Context; import org.junit.Test; @@ -115,7 +114,7 @@ private TestRootNode setup(BaseNode node, Object receiver) { context.initialize(ProxyLanguage.ID); context.enter(); TestRootNode root = new TestRootNode(TestLanguage.getCurrentLanguage(), node, receiver); - GraalTruffleRuntime.getRuntime().createCallTarget(root); + root.getCallTarget(); context.leave(); return root; } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AbstractSplittingStrategyTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AbstractSplittingStrategyTest.java index 4a25d91ac58d..c12fbdb541cc 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AbstractSplittingStrategyTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AbstractSplittingStrategyTest.java @@ -134,7 +134,7 @@ protected static void reflectivelySetField(Object o, String fieldName, Object va protected static void createDummyTargetsToBoostGrowingSplitLimit() { for (int i = 0; i < 10; i++) { - runtime.createCallTarget(new DummyRootNode()); + new DummyRootNode().getCallTarget(); } } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AgnosticInliningPhaseTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AgnosticInliningPhaseTest.java index 5174697b39ca..7701221859c1 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AgnosticInliningPhaseTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AgnosticInliningPhaseTest.java @@ -91,13 +91,13 @@ public boolean hasNextTier() { return request.graph; } - protected final OptimizedCallTarget createDummyNode() { - return (OptimizedCallTarget) runtime.createCallTarget(new RootNode(null) { + protected static final OptimizedCallTarget createDummyNode() { + return (OptimizedCallTarget) new RootNode(null) { @Override public Object execute(VirtualFrame frame) { return null; } - }); + }.getCallTarget(); } protected class CallsInnerNodeTwice extends RootNode { diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AllocationReporterPartialEvaluationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AllocationReporterPartialEvaluationTest.java index 8fe0b00967cd..4a6cad5a3184 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AllocationReporterPartialEvaluationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AllocationReporterPartialEvaluationTest.java @@ -28,13 +28,11 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import org.graalvm.compiler.truffle.runtime.GraalTruffleRuntime; import org.graalvm.compiler.truffle.runtime.OptimizedCallTarget; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.PolyglotAccess; import org.junit.Test; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.AllocationEvent; @@ -52,8 +50,6 @@ */ public class AllocationReporterPartialEvaluationTest extends TestWithSynchronousCompiling { - private static final GraalTruffleRuntime runtime = (GraalTruffleRuntime) Truffle.getRuntime(); - @Test public void testConsistentAssertions() { // Test that onEnter()/onReturnValue() are not broken @@ -64,20 +60,20 @@ public void testConsistentAssertions() { assertNotNull(tester); final AllocationReporter reporter = (AllocationReporter) context.getPolyglotBindings().getMember(AllocationReporter.class.getSimpleName()).asHostObject(); final Long[] value = new Long[]{1L}; - OptimizedCallTarget enterTarget = (OptimizedCallTarget) runtime.createCallTarget(new RootNode(null) { + OptimizedCallTarget enterTarget = (OptimizedCallTarget) new RootNode(null) { @Override public Object execute(VirtualFrame frame) { reporter.onEnter(value[0], 4, 8); return null; } - }); - OptimizedCallTarget returnTarget = (OptimizedCallTarget) runtime.createCallTarget(new RootNode(null) { + }.getCallTarget(); + OptimizedCallTarget returnTarget = (OptimizedCallTarget) new RootNode(null) { @Override public Object execute(VirtualFrame frame) { reporter.onReturnValue(value[0], 4, 8); return null; } - }); + }.getCallTarget(); // Interpret both: assertNotCompiled(enterTarget); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AssumedValuePartialEvaluationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AssumedValuePartialEvaluationTest.java index 4a223433ac01..46ce97d04eff 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AssumedValuePartialEvaluationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/AssumedValuePartialEvaluationTest.java @@ -24,10 +24,6 @@ */ package org.graalvm.compiler.truffle.test; -import com.oracle.truffle.api.Truffle; -import com.oracle.truffle.api.frame.FrameDescriptor; -import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.utilities.AssumedValue; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.truffle.runtime.OptimizedCallTarget; import org.graalvm.compiler.truffle.test.nodes.AbstractTestNode; @@ -35,6 +31,10 @@ import org.junit.Assert; import org.junit.Test; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.utilities.AssumedValue; + public class AssumedValuePartialEvaluationTest extends PartialEvaluationTest { public static Object constant42() { @@ -73,7 +73,7 @@ public void testDynamic() { AssumedValue value = new AssumedValue<>(42); RootTestNode root = new RootTestNode(new FrameDescriptor(), "assumedValue", new ReadDynamicAssumedValueNode()); - OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(root); + OptimizedCallTarget target = (OptimizedCallTarget) root.getCallTarget(); StructuredGraph graph = partialEval(target, new Object[]{value}); compile(target, graph); @@ -87,7 +87,7 @@ public void testDynamicNoDeopt() { AssumedValue value = new AssumedValue<>(42); RootTestNode root = new RootTestNode(new FrameDescriptor(), "assumedValue", new ReadDynamicAssumedValueNode()); - OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(root); + OptimizedCallTarget target = (OptimizedCallTarget) root.getCallTarget(); StructuredGraph graph = partialEval(target, new Object[]{value}); compile(target, graph); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/BytecodeInterpreterPartialEvaluationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/BytecodeInterpreterPartialEvaluationTest.java index f788de91a007..2f5a99971334 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/BytecodeInterpreterPartialEvaluationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/BytecodeInterpreterPartialEvaluationTest.java @@ -40,7 +40,6 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.FrameSlot; import com.oracle.truffle.api.frame.FrameSlotKind; @@ -257,7 +256,7 @@ public static Object constant42() { } private static void assertReturns42(RootNode program) { - Object result = Truffle.getRuntime().createCallTarget(program).call(); + Object result = program.getCallTarget().call(); Assert.assertEquals(Integer.valueOf(42), result); } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/BytecodeOSRNodeTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/BytecodeOSRNodeTest.java index 2d58147c9534..f7b81e521662 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/BytecodeOSRNodeTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/BytecodeOSRNodeTest.java @@ -24,6 +24,19 @@ */ package org.graalvm.compiler.truffle.test; +import java.util.concurrent.TimeUnit; + +import org.graalvm.compiler.test.GraalTest; +import org.graalvm.compiler.truffle.runtime.BytecodeOSRMetadata; +import org.graalvm.compiler.truffle.runtime.FrameWithoutBoxing; +import org.graalvm.compiler.truffle.runtime.GraalTruffleRuntime; +import org.graalvm.compiler.truffle.runtime.OptimizedCallTarget; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; + import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; @@ -38,29 +51,16 @@ import com.oracle.truffle.api.frame.FrameSlotKind; import com.oracle.truffle.api.frame.FrameSlotTypeException; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.BytecodeOSRNode; +import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; -import org.graalvm.compiler.truffle.runtime.BytecodeOSRMetadata; -import org.graalvm.compiler.truffle.runtime.FrameWithoutBoxing; -import org.graalvm.compiler.truffle.runtime.GraalTruffleRuntime; -import org.graalvm.compiler.truffle.runtime.OptimizedCallTarget; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestRule; -import org.junit.rules.Timeout; - -import java.util.concurrent.TimeUnit; public class BytecodeOSRNodeTest extends TestWithSynchronousCompiling { private static final GraalTruffleRuntime runtime = (GraalTruffleRuntime) Truffle.getRuntime(); - // 20s timeout - @Rule public TestRule timeout = new Timeout(30, TimeUnit.SECONDS); + @Rule public TestRule timeout = GraalTest.createTimeout(30, TimeUnit.SECONDS); private int osrThreshold; @@ -79,7 +79,7 @@ public void before() { @Test public void testSimpleInterpreterLoop() { RootNode rootNode = new Program(new InfiniteInterpreterLoop(), new FrameDescriptor()); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); // Interpreter invocation should be OSR compiled and break out of the interpreter loop. Assert.assertEquals(42, target.call()); } @@ -92,7 +92,7 @@ public void testFixedIterationLoop() { FrameDescriptor frameDescriptor = new FrameDescriptor(); FixedIterationLoop osrNode = new FixedIterationLoop(frameDescriptor); RootNode rootNode = new Program(osrNode, frameDescriptor); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); Assert.assertEquals(FixedIterationLoop.OSR_RESULT, target.call(osrThreshold + 1)); } @@ -104,7 +104,7 @@ public void testFixedIterationLoopBelowThreshold() { FrameDescriptor frameDescriptor = new FrameDescriptor(); FixedIterationLoop osrNode = new FixedIterationLoop(frameDescriptor); RootNode rootNode = new Program(osrNode, frameDescriptor); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); Assert.assertEquals(FixedIterationLoop.NORMAL_RESULT, target.call(osrThreshold)); } @@ -117,21 +117,21 @@ public void testMultipleLoops() { FrameDescriptor frameDescriptor = new FrameDescriptor(); TwoFixedIterationLoops osrNode = new TwoFixedIterationLoops(frameDescriptor); RootNode rootNode = new Program(osrNode, frameDescriptor); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); Assert.assertEquals(TwoFixedIterationLoops.OSR_IN_FIRST_LOOP, target.call(osrThreshold + 1)); // Each loop runs for osrThreshold/2 + 1 iterations, so the second loop should trigger OSR. frameDescriptor = new FrameDescriptor(); osrNode = new TwoFixedIterationLoops(frameDescriptor); rootNode = new Program(osrNode, frameDescriptor); - target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + target = (OptimizedCallTarget) rootNode.getCallTarget(); Assert.assertEquals(TwoFixedIterationLoops.OSR_IN_SECOND_LOOP, target.call(osrThreshold / 2 + 1)); // Each loop runs for osrThreshold/2 iterations, so OSR should not get triggered. frameDescriptor = new FrameDescriptor(); osrNode = new TwoFixedIterationLoops(frameDescriptor); rootNode = new Program(osrNode, frameDescriptor); - target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + target = (OptimizedCallTarget) rootNode.getCallTarget(); Assert.assertEquals(TwoFixedIterationLoops.NO_OSR, target.call(osrThreshold / 2)); } @@ -143,7 +143,7 @@ public void testFailedCompilation() { FrameDescriptor frameDescriptor = new FrameDescriptor(); UncompilableFixedIterationLoop osrNode = new UncompilableFixedIterationLoop(frameDescriptor); RootNode rootNode = new Program(osrNode, frameDescriptor); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); Assert.assertEquals(FixedIterationLoop.NORMAL_RESULT, target.call(osrThreshold + 1)); // Compilation should be disabled after a compilation failure. Assert.assertEquals(osrNode.getGraalOSRMetadata(), BytecodeOSRMetadata.DISABLED); @@ -157,7 +157,7 @@ public void testDeoptimizeAndRecompile() { FrameDescriptor frameDescriptor = new FrameDescriptor(); DeoptimizingFixedIterationLoop osrNode = new DeoptimizingFixedIterationLoop(frameDescriptor); RootNode rootNode = new Program(osrNode, frameDescriptor); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); // After osrThreshold+1 iterations, it should trigger OSR and deoptimize. OSR should not be // disabled, but the target should be invalid pending recompilation. Assert.assertEquals(FixedIterationLoop.NORMAL_RESULT, target.call(osrThreshold + 1)); @@ -183,7 +183,7 @@ public void testInvalidateOnNodeReplaced() { }; FixedIterationLoop osrNode = new FixedIterationLoopWithChild(frameDescriptor, childToReplace); RootNode rootNode = new Program(osrNode, frameDescriptor); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); Assert.assertEquals(FixedIterationLoop.OSR_RESULT, target.call(osrThreshold + 1)); BytecodeOSRMetadata osrMetadata = osrNode.getGraalOSRMetadata(); OptimizedCallTarget osrTarget = osrMetadata.getOSRCompilations().get(BytecodeOSRTestNode.DEFAULT_TARGET); @@ -214,7 +214,7 @@ public void testOSRWithMaterializeableFrame() { runtime.markFrameMaterializeCalled(frameDescriptor); MaterializedFixedIterationLoop osrNode = new MaterializedFixedIterationLoop(frameDescriptor); RootNode rootNode = new Program(osrNode, frameDescriptor); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); // OSR should succeed. Assert.assertEquals(FixedIterationLoop.OSR_RESULT, target.call(osrThreshold + 1)); // Since the frame could be materialized, we should reuse the parent frame instead of @@ -235,7 +235,7 @@ public void testOSRPolling() { ); InfiniteInterpreterLoop osrNode = new InfiniteInterpreterLoop(); RootNode rootNode = new Program(osrNode, new FrameDescriptor()); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); Assert.assertEquals(42, target.call()); BytecodeOSRMetadata osrMetadata = osrNode.getGraalOSRMetadata(); int backEdgeCount = osrMetadata.getBackEdgeCount(); @@ -249,7 +249,7 @@ public void testOSRPolling() { @Test public void testInterpreterStateObject() { RootNode rootNode = new Program(new InterpreterStateInfiniteLoop(), new FrameDescriptor()); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); Assert.assertEquals(42, target.call()); } @@ -259,7 +259,7 @@ public void testInterpreterStateObject() { @Test public void testBeforeTransferCallback() { RootNode rootNode = new Program(new BeforeTransferInfiniteLoop(), new FrameDescriptor()); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); Assert.assertEquals(42, target.call()); } @@ -271,7 +271,7 @@ public void testStackTraceHidesOSRCallTarget() { FrameDescriptor frameDescriptor = new FrameDescriptor(); CheckStackWalkCallTarget osrNode = new CheckStackWalkCallTarget(frameDescriptor); RootNode rootNode = new Program(osrNode, frameDescriptor); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); Assert.assertEquals(FixedIterationLoop.OSR_RESULT, target.call(2 * osrThreshold)); } @@ -283,7 +283,7 @@ public void testStackTraceUsesOSRFrame() { FrameDescriptor frameDescriptor = new FrameDescriptor(); CheckStackWalkFrame osrNode = new CheckStackWalkFrame(frameDescriptor); RootNode rootNode = new Program(osrNode, frameDescriptor); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); osrNode.callTarget = target; // set the call target so stack walking can use it Assert.assertEquals(FixedIterationLoop.OSR_RESULT, target.call(2 * osrThreshold)); } @@ -297,7 +297,7 @@ public void testStackTraceUsesNewestOSRFrame() { FrameDescriptor frameDescriptor = new FrameDescriptor(); CheckStackWalkFrameNested osrNode = new CheckStackWalkFrameNested(frameDescriptor); RootNode rootNode = new Program(osrNode, frameDescriptor); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); osrNode.callTarget = target; // set the call target so stack walking can use it Assert.assertEquals(FixedIterationLoop.OSR_RESULT, target.call(3 * osrThreshold)); Assert.assertTrue(osrNode.hasDeoptimizedYet); @@ -314,9 +314,9 @@ public void testGetCallerFrameSkipsOSR() { FrameDescriptor frameDescriptor = new FrameDescriptor(); CheckGetCallerFrameSkipsOSR osrNode = new CheckGetCallerFrameSkipsOSR(frameDescriptor); RootNode rootNode = new Program(osrNode, frameDescriptor); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); RootNode caller = new CheckGetCallerFrameSkipsOSR.Caller(target); - OptimizedCallTarget callerTarget = (OptimizedCallTarget) runtime.createCallTarget(caller); + OptimizedCallTarget callerTarget = (OptimizedCallTarget) caller.getCallTarget(); osrNode.caller = callerTarget; Assert.assertEquals(FixedIterationLoop.OSR_RESULT, callerTarget.call(osrThreshold + 1)); } @@ -328,7 +328,7 @@ public void testGetCallerFrameSkipsOSR() { public void testFrameTransfer() { FrameDescriptor frameDescriptor = new FrameDescriptor(); RootNode rootNode = new Program(new FrameTransferringNode(frameDescriptor), frameDescriptor); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); Assert.assertEquals(42, target.call()); } @@ -340,7 +340,7 @@ public void testFrameTransfer() { public void testFrameTransferWithTagUpdate() { FrameDescriptor frameDescriptor = new FrameDescriptor(); RootNode rootNode = new Program(new FrameTransferringNodeWithTagUpdate(frameDescriptor), frameDescriptor); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); Assert.assertEquals(42, target.call()); } @@ -357,7 +357,7 @@ public void testFrameTransferWithUninitializedSlots() { // use a non-null default value to make sure it gets copied properly. FrameDescriptor frameDescriptor = new FrameDescriptor(new Object()); RootNode rootNode = new Program(new FrameTransferringNodeWithUninitializedSlots(frameDescriptor), frameDescriptor); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); Assert.assertEquals(42, target.call()); } @@ -370,7 +370,7 @@ public void testFrameChanges() { FrameDescriptor frameDescriptor = new FrameDescriptor(); FrameChangingNode osrNode = new FrameChangingNode(frameDescriptor); RootNode rootNode = new Program(osrNode, frameDescriptor); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); Assert.assertEquals(42, target.call()); Assert.assertEquals(2, osrNode.osrCount); } @@ -411,7 +411,7 @@ public void testOSRInBytecodeLoop() { FrameDescriptor frameDescriptor = new FrameDescriptor(); BytecodeNode bytecodeNode = new BytecodeNode(3, frameDescriptor, tripleInput1); RootNode rootNode = new Program(bytecodeNode, frameDescriptor); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); // note: requires an extra iteration due to an awkward interaction with enterprise loop // peeling. Assert.assertEquals(3 * (osrThreshold + 2), target.call(osrThreshold + 2, 0)); @@ -428,7 +428,7 @@ public void testNoOSRInBytecodeLoop() { FrameDescriptor frameDescriptor = new FrameDescriptor(); BytecodeNode bytecodeNode = new BytecodeNode(3, frameDescriptor, tripleInput1); RootNode rootNode = new Program(bytecodeNode, frameDescriptor); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); Assert.assertEquals(3 * osrThreshold, target.call(osrThreshold, 0)); Assert.assertFalse(bytecodeNode.compiled); BytecodeOSRMetadata osrMetadata = (BytecodeOSRMetadata) bytecodeNode.getOSRMetadata(); @@ -443,7 +443,7 @@ public void testOSRInBytecodeOuterLoop() { FrameDescriptor frameDescriptor = new FrameDescriptor(); BytecodeNode bytecodeNode = new BytecodeNode(4, frameDescriptor, multiplyInputs); RootNode rootNode = new Program(bytecodeNode, frameDescriptor); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); Assert.assertEquals(2 * osrThreshold, target.call(osrThreshold, 2)); Assert.assertTrue(bytecodeNode.compiled); BytecodeOSRMetadata osrMetadata = (BytecodeOSRMetadata) bytecodeNode.getOSRMetadata(); @@ -461,7 +461,7 @@ public void testOSRInBytecodeInnerLoop() { FrameDescriptor frameDescriptor = new FrameDescriptor(); BytecodeNode bytecodeNode = new BytecodeNode(4, frameDescriptor, multiplyInputs); RootNode rootNode = new Program(bytecodeNode, frameDescriptor); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); Assert.assertEquals(2 * (osrThreshold - 1), target.call(2, osrThreshold - 1)); Assert.assertTrue(bytecodeNode.compiled); BytecodeOSRMetadata osrMetadata = (BytecodeOSRMetadata) bytecodeNode.getOSRMetadata(); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/CastExactPartialEvaluationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/CastExactPartialEvaluationTest.java index da874e7c0376..e73ac3aab0cd 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/CastExactPartialEvaluationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/CastExactPartialEvaluationTest.java @@ -38,7 +38,6 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.RootCallTarget; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.RootNode; @@ -105,7 +104,7 @@ public void byteBufferAccessIndex() { private void testCommon(AbstractTestNode testNode, String testName) { FrameDescriptor fd = new FrameDescriptor(); RootNode rootNode = new RootTestNode(fd, testName, testNode); - RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode); + RootCallTarget callTarget = rootNode.getCallTarget(); Assert.assertEquals(42, callTarget.call(newBuffer())); assertPartialEvalNoInvokes(callTarget, new Object[]{newBuffer()}); } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ClearFrameSlotTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ClearFrameSlotTest.java index b14bd96d0c03..e97abe151e3e 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ClearFrameSlotTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ClearFrameSlotTest.java @@ -49,7 +49,6 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.RootCallTarget; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.FrameSlot; import com.oracle.truffle.api.frame.FrameSlotKind; @@ -283,7 +282,7 @@ private void doTest(Supplier rootProvider, Consumer g setupContext(Context.newBuilder().option("engine.ForceFrameLivenessAnalysis", "true")); } RootNode rootNode = rootProvider.get(); - RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode); + RootCallTarget callTarget = rootNode.getCallTarget(); StructuredGraph graph = null; try { callTarget.call(args); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/CodeInvalidationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/CodeInvalidationTest.java index 5facd40e2448..e873da6858f6 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/CodeInvalidationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/CodeInvalidationTest.java @@ -258,7 +258,7 @@ public void testInvalidation() throws IOException, InterruptedException { protected synchronized CallTarget parse(ParsingRequest request) { com.oracle.truffle.api.source.Source source = request.getSource(); if (target == null) { - target = Truffle.getRuntime().createCallTarget(new RootNode(languageInstance) { + target = new RootNode(languageInstance) { @Node.Child private volatile BaseNode child = testedCode; @@ -272,7 +272,7 @@ public SourceSection getSourceSection() { return source.createSection(1); } - }); + }.getCallTarget(); } return target; } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/CompilationMemoryTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/CompilationMemoryTest.java index 2e89039c992b..ae66ac8af5fb 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/CompilationMemoryTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/CompilationMemoryTest.java @@ -24,17 +24,18 @@ */ package org.graalvm.compiler.truffle.test; -import com.oracle.truffle.api.Truffle; -import com.oracle.truffle.api.interop.TruffleObject; -import com.oracle.truffle.api.nodes.RootNode; -import com.oracle.truffle.api.test.GCUtils; import java.lang.ref.Reference; import java.lang.ref.WeakReference; + import org.graalvm.compiler.truffle.runtime.OptimizedCallTarget; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.api.test.GCUtils; + public class CompilationMemoryTest extends TestWithPolyglotOptions { @Before @@ -45,7 +46,7 @@ public void setUp() { @Test public void testFieldsFreedAfterCompilation() { TestObject expected = new TestObject(); - OptimizedCallTarget callTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(expected)); + OptimizedCallTarget callTarget = (OptimizedCallTarget) RootNode.createConstantNode(expected).getCallTarget(); Assert.assertEquals(expected, callTarget.call()); Assert.assertEquals(expected, callTarget.call()); Assert.assertTrue(callTarget.isValid()); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/CompilerLoggingTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/CompilerLoggingTest.java index 82af56ac3f6c..4b50d97c98e6 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/CompilerLoggingTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/CompilerLoggingTest.java @@ -54,7 +54,7 @@ public void testLogging() throws IOException { TestListener listener = new TestListener(); try { runtime.addListener(listener); - OptimizedCallTarget compilable = (OptimizedCallTarget) runtime.createCallTarget(RootNode.createConstantNode(true)); + OptimizedCallTarget compilable = (OptimizedCallTarget) RootNode.createConstantNode(true).getCallTarget(); compilable.call(); String logContent = new String(logOut.toByteArray()); String expected = String.format(FORMAT_SUCCESS + "%s%s%n", compilable.getName(), MESSAGE_TO_STREAM, MESSAGE_TO_TTY); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ContextLookupCompilationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ContextLookupCompilationTest.java index 393d7ea59abd..74585745bed1 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ContextLookupCompilationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ContextLookupCompilationTest.java @@ -36,11 +36,13 @@ import org.graalvm.compiler.nodes.FieldLocationIdentity; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.memory.ReadNode; +import org.graalvm.compiler.truffle.runtime.GraalTruffleRuntime; import org.graalvm.compiler.truffle.runtime.OptimizedCallTarget; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Engine; import org.graalvm.word.LocationIdentity; import org.junit.Assert; +import org.junit.Assume; import org.junit.Test; import com.oracle.truffle.api.CompilerAsserts; @@ -48,6 +50,7 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.ContextLocal; import com.oracle.truffle.api.ContextThreadLocal; +import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleContext; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.TruffleLanguage.ContextPolicy; @@ -92,6 +95,16 @@ private static Context enter(Context context) { return context; } + /* + * This test verifies that JVMCI has all the features it needs for a GraalTruffleRuntime. + */ + @Test + public void testJVMCIIsLatest() { + Assume.assumeTrue(Truffle.getRuntime() instanceof GraalTruffleRuntime); + GraalTruffleRuntime runtime = (GraalTruffleRuntime) Truffle.getRuntime(); + assertTrue(runtime.isLatestJVMCI()); + } + @Test public void testContextLocalRead() { Engine engine = Engine.create(); @@ -267,6 +280,7 @@ public void testInnerContexts() { assertLookupsInnerContext(); } finally { innerContext.leave(null, prev); + innerContext.close(); } assertLookupsInnerContext(); context.leave(); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ControlFlowExceptionPartialEvaluationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ControlFlowExceptionPartialEvaluationTest.java index 3ead4bbf2d4a..ee2f908b3d76 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ControlFlowExceptionPartialEvaluationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ControlFlowExceptionPartialEvaluationTest.java @@ -67,7 +67,7 @@ public void catchControlFlowExceptionWithLoopExplosion() { @Test public void catchControlFlowExceptionFromCall() { setupContext(Context.newBuilder().allowExperimentalOptions(true).option("engine.Inlining", "true").build()); - CallTarget callTarget = Truffle.getRuntime().createCallTarget(new RootTestNode(new FrameDescriptor(), "throwControlFlowException", new ThrowControlFlowExceptionTestNode())); + CallTarget callTarget = new RootTestNode(new FrameDescriptor(), "throwControlFlowException", new ThrowControlFlowExceptionTestNode()).getCallTarget(); AbstractTestNode result = new CatchControlFlowExceptionTestNode(new CallTestNode(callTarget)); assertPartialEvalEquals(ControlFlowExceptionPartialEvaluationTest::constant42, new RootTestNode(new FrameDescriptor(), "catchControlFlowExceptionFromCall", result)); } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/DFAPartialEvaluationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/DFAPartialEvaluationTest.java index e666a0c63902..b64a65cd8dfd 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/DFAPartialEvaluationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/DFAPartialEvaluationTest.java @@ -31,7 +31,6 @@ import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; @@ -302,7 +301,7 @@ private RootNode createRootNode(int initialState, DFAStateNode[] states) { } private static void assertMatches(RootNode program, String input) { - Object result = Truffle.getRuntime().createCallTarget(program).call(input); + Object result = program.getCallTarget().call(input); Assert.assertEquals(Boolean.TRUE, result); } @@ -312,7 +311,7 @@ public static boolean constantTrue() { private void assertPartialEvalEqualsAndRunsCorrect(RootNode program, String input) { assertMatches(program, input); - final OptimizedCallTarget compilable = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(program); + final OptimizedCallTarget compilable = (OptimizedCallTarget) program.getCallTarget(); partialEval(compilable, new Object[]{input}, getCompilationId(compilable)); // fail on Exceptions only for now } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/EncodedGraphCacheTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/EncodedGraphCacheTest.java index de58af75ee45..1a3c2d8214f4 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/EncodedGraphCacheTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/EncodedGraphCacheTest.java @@ -124,9 +124,8 @@ private static boolean encodedGraphCacheContains(TruffleCompilerImpl compiler, R @SuppressWarnings("try") private static OptimizedCallTarget compileAST(RootNode rootNode) { - GraalTruffleRuntime runtime = GraalTruffleRuntime.getRuntime(); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); - DebugContext debug = new DebugContext.Builder(runtime.getGraalOptions(OptionValues.class)).build(); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); + DebugContext debug = new DebugContext.Builder(GraalTruffleRuntime.getRuntime().getGraalOptions(OptionValues.class)).build(); try (DebugContext.Scope s = debug.scope("EncodedGraphCacheTest")) { CompilationIdentifier compilationId = getTruffleCompilerFromRuntime(target).createCompilationIdentifier(target); getTruffleCompilerFromRuntime(target).compileAST(target.getOptionValues(), debug, target, compilationId, null, null); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/EngineModeTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/EngineModeTest.java index 07d44f0ecfe0..5c46f8ca7f53 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/EngineModeTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/EngineModeTest.java @@ -63,7 +63,7 @@ private static void compileAndAssertLatency(OptimizedCallTarget target) { @Test public void testLatencyFirstTierOnly() { setupContext(MODE, LATENCY); - OptimizedCallTarget target = (OptimizedCallTarget) GraalTruffleRuntime.getRuntime().createCallTarget(new RootNode(null) { + OptimizedCallTarget target = (OptimizedCallTarget) new RootNode(null) { @Override public Object execute(VirtualFrame frame) { if (GraalCompilerDirectives.hasNextTier()) { @@ -71,7 +71,7 @@ public Object execute(VirtualFrame frame) { } return null; } - }); + }.getCallTarget(); compileAndAssertLatency(target); } @@ -82,7 +82,7 @@ public void testLatencyNoSplitting() { AbstractSplittingStrategyTest.SplitCountingListener listener = new AbstractSplittingStrategyTest.SplitCountingListener(); try { runtime.addListener(listener); - OptimizedCallTarget inner = (OptimizedCallTarget) runtime.createCallTarget(new RootNode(null) { + OptimizedCallTarget inner = (OptimizedCallTarget) new RootNode(null) { @Override public Object execute(VirtualFrame frame) { reportPolymorphicSpecialize(); @@ -93,11 +93,11 @@ public Object execute(VirtualFrame frame) { public boolean isCloningAllowed() { return true; } - }); + }.getCallTarget(); DirectCallNode directCallNode = runtime.createDirectCallNode(inner); DirectCallNode directCallNode2 = runtime.createDirectCallNode(inner); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(new RootNode(null) { + OptimizedCallTarget target = (OptimizedCallTarget) new RootNode(null) { @Override public Object execute(VirtualFrame frame) { directCallNode.call(); @@ -109,7 +109,7 @@ public Object execute(VirtualFrame frame) { public boolean isCloningAllowed() { return true; } - }); + }.getCallTarget(); compileAndAssertLatency(target); Assert.assertEquals("Should not be splitting in latency mode", 0, listener.splitCount); } finally { @@ -121,7 +121,7 @@ public boolean isCloningAllowed() { public void testLatencyNoInlining() { setupContext(MODE, LATENCY, "engine.CompileOnly", ROOT); GraalTruffleRuntime runtime = GraalTruffleRuntime.getRuntime(); - OptimizedCallTarget inner = (OptimizedCallTarget) runtime.createCallTarget(new RootNode(null) { + OptimizedCallTarget inner = (OptimizedCallTarget) new RootNode(null) { @Override public Object execute(VirtualFrame frame) { if (CompilerDirectives.inCompiledCode()) { @@ -139,11 +139,11 @@ private void fail() { public boolean isCloningAllowed() { return true; } - }); + }.getCallTarget(); DirectCallNode directCallNode = runtime.createDirectCallNode(inner); DirectCallNode directCallNode2 = runtime.createDirectCallNode(inner); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(new RootNode(null) { + OptimizedCallTarget target = (OptimizedCallTarget) new RootNode(null) { @Override public Object execute(VirtualFrame frame) { directCallNode.call(); @@ -155,7 +155,7 @@ public Object execute(VirtualFrame frame) { public String getName() { return ROOT; } - }); + }.getCallTarget(); compileAndAssertLatency(target); Assert.assertNull(directCallNode.getClonedCallTarget()); Assert.assertNull(directCallNode2.getClonedCallTarget()); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ExceptionActionTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ExceptionActionTest.java index 093a99157218..c871d856ad5a 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ExceptionActionTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ExceptionActionTest.java @@ -24,12 +24,6 @@ */ package org.graalvm.compiler.truffle.test; -import com.oracle.truffle.api.CompilerAsserts; -import com.oracle.truffle.api.OptimizationFailedException; -import com.oracle.truffle.api.Truffle; -import com.oracle.truffle.api.frame.FrameDescriptor; -import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.RootNode; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -39,10 +33,11 @@ import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.Supplier; -import java.util.regex.Pattern; import java.util.logging.FileHandler; import java.util.logging.SimpleFormatter; +import java.util.regex.Pattern; import java.util.stream.Collectors; + import org.graalvm.compiler.core.GraalCompilerOptions; import org.graalvm.compiler.test.SubprocessUtil; import org.graalvm.compiler.truffle.common.TruffleCompilerRuntime; @@ -50,9 +45,15 @@ import org.graalvm.compiler.truffle.test.nodes.AbstractTestNode; import org.graalvm.compiler.truffle.test.nodes.RootTestNode; import org.graalvm.polyglot.Context; -import org.junit.Test; import org.junit.Assert; import org.junit.BeforeClass; +import org.junit.Test; + +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.OptimizationFailedException; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.RootNode; public class ExceptionActionTest extends TestWithPolyglotOptions { @@ -66,7 +67,7 @@ public class ExceptionActionTest extends TestWithPolyglotOptions { @BeforeClass public static void setUp() { - Truffle.getRuntime().createCallTarget(createPermanentBailoutNode()).call(); + createPermanentBailoutNode().getCallTarget().call(); } @Test @@ -190,7 +191,7 @@ private void executeForked(Consumer verifier, Supplier r verifier.accept(log); } else { setupContext(contextOptions); - OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(rootNodeFactory.get()); + OptimizedCallTarget target = (OptimizedCallTarget) rootNodeFactory.get().getCallTarget(); try { target.call(); } catch (RuntimeException e) { diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ExplodeLoopBlockDuplicationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ExplodeLoopBlockDuplicationTest.java index e92ed4a54ef7..e151aff045ae 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ExplodeLoopBlockDuplicationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ExplodeLoopBlockDuplicationTest.java @@ -29,7 +29,6 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.dsl.UnsupportedSpecializationException; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; @@ -45,7 +44,7 @@ public class ExplodeLoopBlockDuplicationTest extends TestWithSynchronousCompilin */ @Test public void testBlockDuplication() { - OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(new ObjectCacheTestRootNode()); + OptimizedCallTarget target = (OptimizedCallTarget) new ObjectCacheTestRootNode().getCallTarget(); AbstractType value1 = new ConcreteType1(); AbstractType value2 = new ConcreteType2(); target.call(value1); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/FlushEngineQueueTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/FlushEngineQueueTest.java index 7d53b3ef5e43..5e7c00cf9bec 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/FlushEngineQueueTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/FlushEngineQueueTest.java @@ -26,7 +26,6 @@ import static org.junit.Assert.assertNotEquals; -import org.graalvm.compiler.truffle.runtime.GraalTruffleRuntime; import org.graalvm.compiler.truffle.runtime.OptimizedCallTarget; import org.graalvm.polyglot.Context; import org.junit.Test; @@ -78,7 +77,7 @@ public void testTargetsDequeuedOnClose() { } private static OptimizedCallTarget createConstantCallTarget(int i) { - return (OptimizedCallTarget) GraalTruffleRuntime.getRuntime().createCallTarget(new RootNode(null) { + return (OptimizedCallTarget) new RootNode(null) { @Override public Object execute(VirtualFrame frame) { @@ -94,7 +93,7 @@ public String getName() { public String toString() { return getName(); } - }); + }.getCallTarget(); } } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/GraalTruffleRuntimeListenerTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/GraalTruffleRuntimeListenerTest.java index 72f119187fae..cbbce3f0a329 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/GraalTruffleRuntimeListenerTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/GraalTruffleRuntimeListenerTest.java @@ -34,6 +34,7 @@ import java.util.Collections; import java.util.List; +import org.graalvm.compiler.truffle.common.TruffleCompilationTask; import org.graalvm.compiler.truffle.common.TruffleCompilerListener; import org.graalvm.compiler.truffle.runtime.GraalTruffleRuntime; import org.graalvm.compiler.truffle.runtime.GraalTruffleRuntimeListener; @@ -56,7 +57,7 @@ public final class GraalTruffleRuntimeListenerTest extends TestWithPolyglotOptio public void testCompilationSuccess() { setupContext("engine.CompileImmediately", "true", "engine.BackgroundCompilation", "false"); GraalTruffleRuntime runtime = GraalTruffleRuntime.getRuntime(); - OptimizedCallTarget compilable = (OptimizedCallTarget) runtime.createCallTarget(RootNode.createConstantNode(true)); + OptimizedCallTarget compilable = (OptimizedCallTarget) RootNode.createConstantNode(true).getCallTarget(); TestListener listener = new TestListener(compilable); try { runtime.addListener(listener); @@ -76,7 +77,7 @@ public void testCompilationSuccess() { public void testCompilationFailure() { setupContext("engine.CompileImmediately", "true", "engine.BackgroundCompilation", "false"); GraalTruffleRuntime runtime = GraalTruffleRuntime.getRuntime(); - OptimizedCallTarget compilable = (OptimizedCallTarget) runtime.createCallTarget(createFailureNode()); + OptimizedCallTarget compilable = (OptimizedCallTarget) createFailureNode().getCallTarget(); TestListener listener = new TestListener(compilable); try { runtime.addListener(listener); @@ -98,7 +99,7 @@ public void write(int b) throws IOException { } }).allowExperimentalOptions(true).option("engine.CompileImmediately", "true").option("engine.BackgroundCompilation", "false").option("engine.CompilationFailureAction", "Diagnose")); GraalTruffleRuntime runtime = GraalTruffleRuntime.getRuntime(); - OptimizedCallTarget compilable = (OptimizedCallTarget) runtime.createCallTarget(createFailureNode()); + OptimizedCallTarget compilable = (OptimizedCallTarget) createFailureNode().getCallTarget(); TestListener listener = new TestListener(compilable); try { runtime.addListener(listener); @@ -121,7 +122,7 @@ public void testBlockCompilation() { "engine.BackgroundCompilation", "false", "engine.PartialBlockCompilationSize", "1"); GraalTruffleRuntime runtime = GraalTruffleRuntime.getRuntime(); - OptimizedCallTarget compilable = (OptimizedCallTarget) runtime.createCallTarget(createBlocks()); + OptimizedCallTarget compilable = (OptimizedCallTarget) createBlocks().getCallTarget(); compilable.computeBlockCompilations(); TestListener listener = new TestListener(compilable); try { @@ -159,7 +160,7 @@ public void testBlockCompilationLargeBlocks() { "engine.PartialBlockCompilationSize", "1", "engine.PartialBlockMaximumSize", "0"); GraalTruffleRuntime runtime = GraalTruffleRuntime.getRuntime(); - OptimizedCallTarget compilable = (OptimizedCallTarget) runtime.createCallTarget(createBlocks()); + OptimizedCallTarget compilable = (OptimizedCallTarget) createBlocks().getCallTarget(); compilable.computeBlockCompilations(); TestListener listener = new TestListener(compilable); try { @@ -198,7 +199,7 @@ public void testBlockCompilationMaximumGraalNodeCount() { children[i] = new ExpensiveTestNode(); } BlockNode block = BlockNode.create(children, new NodeExecutor()); - OptimizedCallTarget compilable = (OptimizedCallTarget) runtime.createCallTarget(new TestRootNode(block)); + OptimizedCallTarget compilable = (OptimizedCallTarget) new TestRootNode(block).getCallTarget(); TestListener listener = new TestListener(compilable); try { runtime.addListener(listener); @@ -373,7 +374,7 @@ public void onCompilationDequeued(OptimizedCallTarget target, Object source, Cha } @Override - public void onCompilationStarted(OptimizedCallTarget target, int tier) { + public void onCompilationStarted(OptimizedCallTarget target, TruffleCompilationTask task) { if (isImportant(target)) { waitForInitialTarget(); events.add(EventType.COMPILATION_STARTED); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/IndirectCallSiteTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/IndirectCallSiteTest.java index fd96927fa482..29c5f3aab5ec 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/IndirectCallSiteTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/IndirectCallSiteTest.java @@ -55,19 +55,19 @@ public void before() { @Test public void testIndirectCallNodeDoesNotDeopOnFirstCall() { final Object[] noArguments = new Object[0]; - final OptimizedCallTarget innerTarget = (OptimizedCallTarget) runtime.createCallTarget(new RootNode(null) { + final OptimizedCallTarget innerTarget = (OptimizedCallTarget) new RootNode(null) { @Override public Object execute(VirtualFrame frame) { return null; } - }); - final OptimizedCallTarget uninitializedInnerTarget = (OptimizedCallTarget) runtime.createCallTarget(new RootNode(null) { + }.getCallTarget(); + final OptimizedCallTarget uninitializedInnerTarget = (OptimizedCallTarget) new RootNode(null) { @Override public Object execute(VirtualFrame frame) { return null; } - }); - final OptimizedCallTarget outerTarget = (OptimizedCallTarget) runtime.createCallTarget(new RootNode(null) { + }.getCallTarget(); + final OptimizedCallTarget outerTarget = (OptimizedCallTarget) new RootNode(null) { @Child OptimizedIndirectCallNode indirectCallNode = (OptimizedIndirectCallNode) runtime.createIndirectCallNode(); @Override @@ -78,7 +78,7 @@ public Object execute(VirtualFrame frame) { return indirectCallNode.call(uninitializedInnerTarget, noArguments); } } - }); + }.getCallTarget(); final int compilationThreshold = outerTarget.getOptionValue(PolyglotCompilerOptions.SingleTierCompilationThreshold); for (int i = 0; i < compilationThreshold; i++) { outerTarget.call(noArguments); @@ -206,11 +206,11 @@ void assertNotDeoptimized(OptimizedCallTarget target) { */ @Test public void testIndirectCallNodeDoesNotDeoptOnTypeChangeWithInlining1() { - final OptimizedCallTarget toInterpreterOnString = (OptimizedCallTarget) runtime.createCallTarget(new WritesToGlobalState()); + final OptimizedCallTarget toInterpreterOnString = (OptimizedCallTarget) new WritesToGlobalState().getCallTarget(); final Object[] directArguments = new Object[]{1}; - final OptimizedCallTarget directCall = (OptimizedCallTarget) runtime.createCallTarget(new DirectlyCallsTargetWithArguments(toInterpreterOnString, directArguments)); - final OptimizedCallTarget noOp = (OptimizedCallTarget) runtime.createCallTarget(new DummyTarget()); - final OptimizedCallTarget indirectCall = (OptimizedCallTarget) runtime.createCallTarget(new IndirectCallTargetFromArgument()); + final OptimizedCallTarget directCall = (OptimizedCallTarget) new DirectlyCallsTargetWithArguments(toInterpreterOnString, directArguments).getCallTarget(); + final OptimizedCallTarget noOp = (OptimizedCallTarget) new DummyTarget().getCallTarget(); + final OptimizedCallTarget indirectCall = (OptimizedCallTarget) new IndirectCallTargetFromArgument().getCallTarget(); final int compilationThreshold = toInterpreterOnString.getOptionValue(PolyglotCompilerOptions.SingleTierCompilationThreshold); @@ -248,10 +248,10 @@ public void testIndirectCallNodeDoesNotDeoptOnTypeChangeWithInlining1() { @Test public void testIndirectCallDoesNotDeoptInliningDirectCaller() { - final OptimizedCallTarget callee = (OptimizedCallTarget) runtime.createCallTarget(RootNode.createConstantNode(0)); + final OptimizedCallTarget callee = (OptimizedCallTarget) RootNode.createConstantNode(0).getCallTarget(); final Object[] directArguments = new Object[]{"direct arg"}; - final OptimizedCallTarget directCall = (OptimizedCallTarget) runtime.createCallTarget(new DirectlyCallsTargetWithArguments(callee, directArguments)); - final OptimizedCallTarget indirectCall = (OptimizedCallTarget) runtime.createCallTarget(new IndirectCallTargetFromArgument()); + final OptimizedCallTarget directCall = (OptimizedCallTarget) new DirectlyCallsTargetWithArguments(callee, directArguments).getCallTarget(); + final OptimizedCallTarget indirectCall = (OptimizedCallTarget) new IndirectCallTargetFromArgument().getCallTarget(); final int compilationThreshold = callee.getOptionValue(PolyglotCompilerOptions.SingleTierCompilationThreshold); try (DeoptInvalidateListener directListener = new DeoptInvalidateListener(runtime, directCall)) { @@ -278,10 +278,10 @@ public void testIndirectCallDoesNotDeoptInliningDirectCaller() { public void testIndirectCallDoesNotDeoptNotInliningDirectCaller() { setupContext("engine.MultiTier", "false", "engine.Inlining", "false"); - final OptimizedCallTarget callee = (OptimizedCallTarget) runtime.createCallTarget(RootNode.createConstantNode(0)); + final OptimizedCallTarget callee = (OptimizedCallTarget) RootNode.createConstantNode(0).getCallTarget(); final Object[] directArguments = new Object[]{"direct arg"}; - final OptimizedCallTarget directCall = (OptimizedCallTarget) runtime.createCallTarget(new DirectlyCallsTargetWithArguments(callee, directArguments)); - final OptimizedCallTarget indirectCall = (OptimizedCallTarget) runtime.createCallTarget(new IndirectCallTargetFromArgument()); + final OptimizedCallTarget directCall = (OptimizedCallTarget) new DirectlyCallsTargetWithArguments(callee, directArguments).getCallTarget(); + final OptimizedCallTarget indirectCall = (OptimizedCallTarget) new IndirectCallTargetFromArgument().getCallTarget(); final int compilationThreshold = callee.getOptionValue(PolyglotCompilerOptions.SingleTierCompilationThreshold); try (DeoptInvalidateListener directListener = new DeoptInvalidateListener(runtime, directCall)) { @@ -305,10 +305,10 @@ public void testIndirectCallDoesNotDeoptNotInliningDirectCaller() { @Test public void testIndirectCallDoesNotDeoptCallee() { - final OptimizedCallTarget callee = (OptimizedCallTarget) runtime.createCallTarget(RootNode.createConstantNode(0)); + final OptimizedCallTarget callee = (OptimizedCallTarget) RootNode.createConstantNode(0).getCallTarget(); final Object[] directArguments = new Object[]{"direct arg"}; - final OptimizedCallTarget directCall = (OptimizedCallTarget) runtime.createCallTarget(new DirectlyCallsTargetWithArguments(callee, directArguments)); - final OptimizedCallTarget indirectCall = (OptimizedCallTarget) runtime.createCallTarget(new IndirectCallTargetFromArgument()); + final OptimizedCallTarget directCall = (OptimizedCallTarget) new DirectlyCallsTargetWithArguments(callee, directArguments).getCallTarget(); + final OptimizedCallTarget indirectCall = (OptimizedCallTarget) new IndirectCallTargetFromArgument().getCallTarget(); final int compilationThreshold = callee.getOptionValue(PolyglotCompilerOptions.SingleTierCompilationThreshold); try (DeoptInvalidateListener calleeListener = new DeoptInvalidateListener(runtime, callee)) { diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/InstrumentBranchesPhaseTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/InstrumentBranchesPhaseTest.java index 7b89c3bba841..213c069afabb 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/InstrumentBranchesPhaseTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/InstrumentBranchesPhaseTest.java @@ -24,22 +24,23 @@ */ package org.graalvm.compiler.truffle.test; -import com.oracle.truffle.api.test.ReflectionUtils; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.truffle.compiler.PartialEvaluator; import org.graalvm.compiler.truffle.compiler.phases.InstrumentPhase; import org.graalvm.compiler.truffle.runtime.OptimizedCallTarget; import org.graalvm.compiler.truffle.test.nodes.AbstractTestNode; import org.graalvm.compiler.truffle.test.nodes.RootTestNode; +import org.graalvm.polyglot.Context; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.VirtualFrame; -import org.graalvm.polyglot.Context; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; +import com.oracle.truffle.api.test.ReflectionUtils; public class InstrumentBranchesPhaseTest extends PartialEvaluationTest { @@ -52,11 +53,14 @@ public SimpleIfTestNode(int constant) { @Override public int execute(VirtualFrame frame) { + int res; if (constant < 0) { - return -1 * constant; + res = -1 * constant; } else { - return 1; + res = 1; } + GraalDirectives.controlFlowAnchor(); + return res; } } @@ -124,7 +128,7 @@ private InstrumentPhase.Instrumentation getInstrumentation(OptimizedCallTarget t public void twoIfsTest() { FrameDescriptor descriptor = new FrameDescriptor(); TwoIfsTestNode result = new TwoIfsTestNode(5, -1); - RootTestNode rootNode = new RootTestNode(descriptor, "twoIfsRoot", result); + RootTestNode rootNode = new RootTestNode(descriptor, "twoIfsRoot", result, true); OptimizedCallTarget target = compileHelper("twoIfsRoot", rootNode, new Object[0]); Assert.assertTrue(target.isValid()); // We run this twice to make sure that it comes first in the sorted access list. diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/LanguageContextFreedTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/LanguageContextFreedTest.java index 5f7f9b3c46d4..a8fb5989cf32 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/LanguageContextFreedTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/LanguageContextFreedTest.java @@ -40,11 +40,9 @@ import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.ContextLocal; import com.oracle.truffle.api.ContextThreadLocal; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.TruffleLanguage.ContextPolicy; import com.oracle.truffle.api.TruffleLanguage.Registration; -import com.oracle.truffle.api.TruffleRuntime; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.test.GCUtils; @@ -154,8 +152,7 @@ protected LanguageContext createContext(Env env) { @Override protected CallTarget parse(TruffleLanguage.ParsingRequest request) throws Exception { - TruffleRuntime runtime = Truffle.getRuntime(); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(new RootNode(this) { + OptimizedCallTarget target = (OptimizedCallTarget) new RootNode(this) { @SuppressWarnings("unchecked") @Override @@ -163,7 +160,7 @@ public Object execute(VirtualFrame frame) { getContextReference0().get(this).currentTarget = (OptimizedCallTarget) getCallTarget(); return true; } - }); + }.getCallTarget(); getContextReference0().get(null).currentTarget = target; assertEquals(COMPILATION_THRESHOLD, (int) target.getOptionValue(PolyglotCompilerOptions.SingleTierCompilationThreshold)); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/LazyClassLoadingTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/LazyClassLoadingTest.java index b5d77628b72b..ecb63059fb76 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/LazyClassLoadingTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/LazyClassLoadingTest.java @@ -55,7 +55,7 @@ import org.junit.Assert; import org.junit.Assume; import org.junit.Test; -import com.oracle.truffle.api.Truffle; + import com.oracle.truffle.api.nodes.RootNode; import jdk.vm.ci.runtime.JVMCICompilerFactory; @@ -90,7 +90,7 @@ private static Class forNameOrNull(String name) { @Test public void testClassLoading() throws IOException, InterruptedException { setupContext(); - OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(0)); + OptimizedCallTarget target = (OptimizedCallTarget) RootNode.createConstantNode(0).getCallTarget(); Assume.assumeFalse(target.getOptionValue(CompileImmediately)); List vmCommandLine = getVMCommandLine(); Assume.assumeFalse("Explicitly enables JVMCI compiler", vmCommandLine.contains("-XX:+UseJVMCINativeLibrary") || vmCommandLine.contains("-XX:+UseJVMCICompiler")); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/LibrarySplittingStrategyTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/LibrarySplittingStrategyTest.java index 917c3d2f6bcf..878f5d629b08 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/LibrarySplittingStrategyTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/LibrarySplittingStrategyTest.java @@ -58,9 +58,9 @@ public void boostBudget() { @Test public void testCachedLibWithValue() { - OptimizedCallTarget callTarget = (OptimizedCallTarget) runtime.createCallTarget( - new SplittingTestRootNode(LibrarySplittingStrategyTestFactory.CachesLibOnValueNodeGen.create( - new ReturnsFirstArgumentNode()))); + OptimizedCallTarget callTarget = (OptimizedCallTarget) new SplittingTestRootNode( + LibrarySplittingStrategyTestFactory.CachesLibOnValueNodeGen.create( + new ReturnsFirstArgumentNode())).getCallTarget(); Object[] first = new Object[]{1}; Object[] second = new Object[]{"2"}; testSplitsDirectCallsHelper(callTarget, first, second); @@ -68,10 +68,9 @@ public void testCachedLibWithValue() { @Test public void testCachedLibWithValueExclude() { - OptimizedCallTarget callTarget = (OptimizedCallTarget) runtime.createCallTarget( - new SplittingTestRootNode( - LibrarySplittingStrategyTestFactory.CachesLibOnValueNodeExcludeNodeGen.create( - new ReturnsFirstArgumentNode()))); + OptimizedCallTarget callTarget = (OptimizedCallTarget) new SplittingTestRootNode( + LibrarySplittingStrategyTestFactory.CachesLibOnValueNodeExcludeNodeGen.create( + new ReturnsFirstArgumentNode())).getCallTarget(); Object[] first = new Object[]{1}; Object[] second = new Object[]{"2"}; testDoesNotSplitDirectCallHelper(callTarget, first, second); @@ -79,10 +78,9 @@ public void testCachedLibWithValueExclude() { @Test public void testExportedMessage() { - OptimizedCallTarget callTarget = (OptimizedCallTarget) runtime.createCallTarget( - new SplittingTestRootNode( - LibrarySplittingStrategyTestFactory.SplitReadPropertyNodeGen.create( - new ReturnsFirstArgumentNode(), new ReturnsSecondArgumentNode()))); + OptimizedCallTarget callTarget = (OptimizedCallTarget) new SplittingTestRootNode( + LibrarySplittingStrategyTestFactory.SplitReadPropertyNodeGen.create( + new ReturnsFirstArgumentNode(), new ReturnsSecondArgumentNode())).getCallTarget(); Object[] first = new Object[]{newInstance(), "a"}; Object[] second = new Object[]{newInstance(), "b"}; testSplitsDirectCallsHelper(callTarget, first, second); @@ -90,10 +88,9 @@ public void testExportedMessage() { @Test public void testExportedMessageWithExcludedSpecialisation() { - OptimizedCallTarget callTarget = (OptimizedCallTarget) runtime.createCallTarget( - new SplittingTestRootNode( - LibrarySplittingStrategyTestFactory.SplitReadPropertyNodeGen.create( - new ReturnsFirstArgumentNode(), new ReturnsSecondArgumentNode()))); + OptimizedCallTarget callTarget = (OptimizedCallTarget) new SplittingTestRootNode( + LibrarySplittingStrategyTestFactory.SplitReadPropertyNodeGen.create( + new ReturnsFirstArgumentNode(), new ReturnsSecondArgumentNode())).getCallTarget(); Object[] first = new Object[]{newInstance(), SplittingObjectType.ReadMember.CACHED_NAME}; Object[] second = new Object[]{newInstance(), "b"}; testDoesNotSplitDirectCallHelper(callTarget, first, second); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/LoopNodeOSRTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/LoopNodeOSRTest.java new file mode 100644 index 000000000000..f2840e095a75 --- /dev/null +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/LoopNodeOSRTest.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.truffle.test; + +import java.util.stream.IntStream; + +import org.graalvm.compiler.truffle.runtime.BytecodeOSRMetadata; +import org.graalvm.compiler.truffle.runtime.OptimizedCallTarget; +import org.junit.Assert; +import org.junit.Test; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.frame.Frame; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; +import com.oracle.truffle.api.frame.FrameSlot; +import com.oracle.truffle.api.frame.FrameSlotKind; +import com.oracle.truffle.api.frame.FrameUtil; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.RepeatingNode; +import com.oracle.truffle.api.nodes.RootNode; + +public class LoopNodeOSRTest extends TestWithSynchronousCompiling { + + static final Object[] ARGUMENTS = IntStream.range(21, 36).mapToObj(Integer::valueOf).toArray(); + + private static class TestLoopRootNode extends RootNode { + @Child private LoopNode loop; + private final FrameSlot iterationSlot; + + TestLoopRootNode(RepeatingNode body, FrameDescriptor frameDescriptor, FrameSlot iterationSlot) { + super(null, frameDescriptor); + this.loop = Truffle.getRuntime().createLoopNode(body); + this.iterationSlot = iterationSlot; + } + + @Override + public Object execute(VirtualFrame frame) { + frame.setInt(iterationSlot, 0); + return loop.execute(frame); + } + } + + private final class CheckStackWalkBody extends Node implements RepeatingNode { + private final int total; + private final FrameSlot iterationSlot; + private final FrameDescriptor frameDescriptor; + boolean compiled; + + private CheckStackWalkBody(int total, FrameDescriptor frameDescriptor, FrameSlot iterationSlot) { + this.total = total; + this.iterationSlot = iterationSlot; + this.frameDescriptor = frameDescriptor; + } + + @Override + public boolean executeRepeating(VirtualFrame frame) { + int iteration = FrameUtil.getIntSafe(frame, iterationSlot); + if (iteration < total) { + if (iteration % (total / 10) == 0) { + checkStack(); + } + iteration++; + frame.setInt(iterationSlot, iteration); + return true; + } else { + if (CompilerDirectives.inCompiledCode()) { + compiled = true; + } + iteration = 0; + frame.setInt(iterationSlot, iteration); + return false; + } + } + + @TruffleBoundary + private void checkStack() { + Truffle.getRuntime().iterateFrames(frameInstance -> { + Frame frame = frameInstance.getFrame(FrameAccess.READ_ONLY); + Assert.assertArrayEquals(ARGUMENTS, frame.getArguments()); + Assert.assertSame(frameDescriptor, frame.getFrameDescriptor()); + return null; + }); + } + } + + @Test + public void testOSRStackFrame() { + int osrThreshold = 10 * BytecodeOSRMetadata.OSR_POLL_INTERVAL; + setupContext("engine.MultiTier", "false", + "engine.OSR", "true", + "engine.OSRCompilationThreshold", String.valueOf(osrThreshold)); + + FrameDescriptor desc = new FrameDescriptor(); + FrameSlot iterationSlot = desc.addFrameSlot("iteration", FrameSlotKind.Int); + CheckStackWalkBody loop = new CheckStackWalkBody(osrThreshold * 2, desc, iterationSlot); + TestLoopRootNode rootNode = new TestLoopRootNode(loop, desc, iterationSlot); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); + + target.call(ARGUMENTS); + + Assert.assertTrue("Loop should have been OSR compiled", loop.compiled); + } + +} diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/LoopNodePartialEvaluationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/LoopNodePartialEvaluationTest.java index ba3a573974c7..3796130670fc 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/LoopNodePartialEvaluationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/LoopNodePartialEvaluationTest.java @@ -31,6 +31,7 @@ import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.ProfileData.ProfileSource; import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; import org.graalvm.compiler.truffle.runtime.OptimizedCallTarget; import org.graalvm.polyglot.Context; import org.junit.Assert; @@ -97,7 +98,7 @@ public void testLoopConditionProfile() { setupContext(Context.newBuilder().allowExperimentalOptions(true).option("engine.CompileImmediately", "false").option("engine.BackgroundCompilation", "false").build()); TestLoopRootNode repeatRootNode = new TestLoopRootNode(new RepeatNTimesNode(9)); - OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(repeatRootNode); + OptimizedCallTarget target = (OptimizedCallTarget) repeatRootNode.getCallTarget(); StructuredGraph graph = partialEval(target, new Object[0]); Stream ifWithInjectedProfile = graph.getNodes().filter(IfNode.class).stream().filter(i -> i.getProfileData().getProfileSource() == ProfileSource.INJECTED); @@ -106,8 +107,9 @@ public void testLoopConditionProfile() { List loopBegins = graph.getNodes().filter(LoopBeginNode.class).snapshot(); Assert.assertEquals(loopBegins.toString(), 1, loopBegins.size()); + ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, false, false, false); for (LoopBeginNode loopBegin : loopBegins) { - Assert.assertEquals("Expected loop frequency", 10.0, loopBegin.loopFrequency(), 0.01); + Assert.assertEquals("Expected loop frequency", 10.0, cfg.localLoopFrequency(loopBegin), 0.01); } } @@ -118,7 +120,7 @@ public void testPrepareLoopForAOT() { setupContext(Context.newBuilder().allowExperimentalOptions(true).option("engine.CompileImmediately", "true").option("engine.BackgroundCompilation", "false").build()); TestLoopRootNode repeatRootNode = new TestLoopRootNode(new RepeatNTimesNode(9)); - OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(repeatRootNode); + OptimizedCallTarget target = (OptimizedCallTarget) repeatRootNode.getCallTarget(); target.prepareForAOT(); StructuredGraph graph = partialEval(target, new Object[0]); @@ -129,8 +131,9 @@ public void testPrepareLoopForAOT() { List loopBegins = graph.getNodes().filter(LoopBeginNode.class).snapshot(); Assert.assertEquals(loopBegins.toString(), 1, loopBegins.size()); + ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, false, false, false); for (LoopBeginNode loopBegin : loopBegins) { - Assert.assertEquals("Expected loop frequency", 2.0, loopBegin.loopFrequency(), 0.01); + Assert.assertEquals("Expected loop frequency", 2.0, cfg.localLoopFrequency(loopBegin), 0.01); } target.compile(true); @@ -254,7 +257,7 @@ public void testPropagateInjectedProfile(boolean twoEnds, boolean trueContinue) setupContext(Context.newBuilder().allowExperimentalOptions(true).option("engine.CompileImmediately", "false").option("engine.BackgroundCompilation", "false").build()); RootNode rootNode = new TestPropagateInjectedProfileRootNode(new TestRepeatingNode(9, twoEnds, trueContinue)); - OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); StructuredGraph graph = partialEval(target, new Object[0]); Stream ifWithInjectedProfile = graph.getNodes().filter(IfNode.class).stream().filter(i -> i.getProfileData().getProfileSource() == ProfileSource.INJECTED); @@ -264,8 +267,9 @@ public void testPropagateInjectedProfile(boolean twoEnds, boolean trueContinue) List loopBegins = graph.getNodes().filter(LoopBeginNode.class).snapshot(); Assert.assertEquals(loopBegins.toString(), 1, loopBegins.size()); + ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, false, false, false); for (LoopBeginNode loopBegin : loopBegins) { - Assert.assertEquals("Expected loop frequency", 10.0, loopBegin.loopFrequency(), 0.01); + Assert.assertEquals("Expected loop frequency", 10.0, cfg.localLoopFrequency(loopBegin), 0.01); } } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/MaterializedFrameTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/MaterializedFrameTest.java index caf71ddd7176..a51f3d938b8c 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/MaterializedFrameTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/MaterializedFrameTest.java @@ -41,7 +41,6 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.RootCallTarget; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.FrameSlot; import com.oracle.truffle.api.frame.FrameSlotKind; @@ -81,7 +80,7 @@ public Object execute(VirtualFrame frame) { @Test public void getFrameSlotKind() { RootNode rootNode = createRootNode(); - RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode); + RootCallTarget callTarget = rootNode.getCallTarget(); StructuredGraph graph = partialEval((OptimizedCallTarget) callTarget, new Object[]{}, getCompilationId(callTarget)); NodeIterable calls = graph.getNodes().filter(MethodCallTargetNode.class); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/MergeExplodeProxyTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/MergeExplodeProxyTest.java index a11e030b259e..f4eea426ef41 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/MergeExplodeProxyTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/MergeExplodeProxyTest.java @@ -37,7 +37,6 @@ import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.FrameSlot; import com.oracle.truffle.api.frame.FrameSlotKind; import com.oracle.truffle.api.frame.FrameSlotTypeException; @@ -211,7 +210,7 @@ public void testLoopControlVariableProxy() { /* 12: */Bytecode.POP, /* 13: */Bytecode.RETURN}; - CallTarget callee = Truffle.getRuntime().createCallTarget(new LoopControlVariableProxy("simpleLoopProgram", bytecodes, 1, 3)); + CallTarget callee = new LoopControlVariableProxy("simpleLoopProgram", bytecodes, 1, 3).getCallTarget(); callee.call(); callee.call(); callee.call(); @@ -394,13 +393,13 @@ public void test01() { /* 12: */Bytecode.POP, /* 13: */Bytecode.RETURN}; - CallTarget callee = Truffle.getRuntime().createCallTarget(new WrongLoopExitMerge("mergedLoopExitProgram", bytecodes, 1, 3)); + CallTarget callee = new WrongLoopExitMerge("mergedLoopExitProgram", bytecodes, 1, 3).getCallTarget(); callee.call(); callee.call(); callee.call(); callee.call(); - CallTarget caller = Truffle.getRuntime().createCallTarget(new Caller(callee)); + CallTarget caller = new Caller(callee).getCallTarget(); caller.call(); caller.call(); caller.call(); @@ -432,7 +431,7 @@ public void test01Caller() { /* 12: */Bytecode.POP, /* 13: */Bytecode.RETURN}; - CallTarget callee = Truffle.getRuntime().createCallTarget(new WrongLoopExitMerge("mergedLoopExitProgram", bytecodes, 1, 3)); + CallTarget callee = new WrongLoopExitMerge("mergedLoopExitProgram", bytecodes, 1, 3).getCallTarget(); callee.call(); callee.call(); callee.call(); @@ -653,8 +652,7 @@ public void testSameValueProxy() { /* 23: */Bytecode.POP, /* 24: */Bytecode.RETURN}; - CallTarget callee = Truffle.getRuntime().createCallTarget( - new ProxySameValueOnce("proxyAtStateProgram", bytecodes, 0, 6)); + CallTarget callee = new ProxySameValueOnce("proxyAtStateProgram", bytecodes, 0, 6).getCallTarget(); ProxySameValueOnce.SideEffect = -1; callee.call(); ProxySameValueOnce.SideEffect = 0; @@ -883,8 +881,7 @@ public void testNoneLiveLoopExitProxy() { /* 23: */Bytecode.POP, /* 24: */Bytecode.RETURN}; - CallTarget callee = Truffle.getRuntime().createCallTarget( - new NoneLiveNoProxyTest("proxyAtStateProgram", bytecodes, 0, 6)); + CallTarget callee = new NoneLiveNoProxyTest("proxyAtStateProgram", bytecodes, 0, 6).getCallTarget(); ProxySameValueOnce.SideEffect = -1; callee.call(); ProxySameValueOnce.SideEffect = 0; diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/MultiTierCompilationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/MultiTierCompilationTest.java index fe4276adc33f..b8a3fca01e10 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/MultiTierCompilationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/MultiTierCompilationTest.java @@ -24,14 +24,12 @@ */ package org.graalvm.compiler.truffle.test; -import static org.graalvm.compiler.truffle.options.PolyglotCompilerOptions.LastTierCompilationThreshold; import static org.graalvm.compiler.truffle.options.PolyglotCompilerOptions.FirstTierCompilationThreshold; +import static org.graalvm.compiler.truffle.options.PolyglotCompilerOptions.LastTierCompilationThreshold; -import com.oracle.truffle.api.nodes.LoopNode; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.RepeatingNode; import org.graalvm.compiler.truffle.runtime.GraalCompilerDirectives; import org.graalvm.compiler.truffle.runtime.OptimizedCallTarget; +import org.graalvm.polyglot.Context; import org.junit.Assert; import org.junit.Test; @@ -40,8 +38,10 @@ import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; +import com.oracle.truffle.api.nodes.LoopNode; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.RepeatingNode; import com.oracle.truffle.api.nodes.RootNode; -import org.graalvm.polyglot.Context; public class MultiTierCompilationTest extends PartialEvaluationTest { @@ -187,8 +187,8 @@ public void testDefault() { "true").option("engine.FirstTierInliningPolicy", "None").option("engine.Splitting", "false").option("engine.FirstTierCompilationThreshold", "100").option( "engine.LastTierCompilationThreshold", "1000").build()); - OptimizedCallTarget calleeTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(new MultiTierCalleeNode()); - OptimizedCallTarget multiTierTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(new MultiTierRootNode(calleeTarget)); + OptimizedCallTarget calleeTarget = (OptimizedCallTarget) new MultiTierCalleeNode().getCallTarget(); + OptimizedCallTarget multiTierTarget = (OptimizedCallTarget) new MultiTierRootNode(calleeTarget).getCallTarget(); final int firstTierCompilationThreshold = calleeTarget.getOptionValue(FirstTierCompilationThreshold); final int compilationThreshold = calleeTarget.getOptionValue(LastTierCompilationThreshold); @@ -214,8 +214,8 @@ public void testFirstTierInlining() { "true").option("engine.FirstTierInliningPolicy", "Default").option("engine.Splitting", "false").option("engine.FirstTierCompilationThreshold", "100").option( "engine.LastTierCompilationThreshold", "1000").build()); - OptimizedCallTarget calleeTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(new MultiTierCalleeNode()); - OptimizedCallTarget multiTierTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(new MultiTierRootNode(calleeTarget)); + OptimizedCallTarget calleeTarget = (OptimizedCallTarget) new MultiTierCalleeNode().getCallTarget(); + OptimizedCallTarget multiTierTarget = (OptimizedCallTarget) new MultiTierRootNode(calleeTarget).getCallTarget(); final int firstTierCompilationThreshold = calleeTarget.getOptionValue(FirstTierCompilationThreshold); final int compilationThreshold = calleeTarget.getOptionValue(LastTierCompilationThreshold); @@ -237,10 +237,10 @@ public void testWhenCalleeCompiledFirst() { "true").option("engine.FirstTierInliningPolicy", "None").option("engine.Splitting", "false").option("engine.FirstTierCompilationThreshold", "100").option( "engine.LastTierCompilationThreshold", "1000").build()); - OptimizedCallTarget calleeTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(new MultiTierCalleeNode()); + OptimizedCallTarget calleeTarget = (OptimizedCallTarget) new MultiTierCalleeNode().getCallTarget(); final int firstTierCompilationThreshold = calleeTarget.getOptionValue(FirstTierCompilationThreshold); final int compilationThreshold = calleeTarget.getOptionValue(LastTierCompilationThreshold); - OptimizedCallTarget multiTierTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(new MultiTierWithFrequentCalleeRootNode(calleeTarget, firstTierCompilationThreshold)); + OptimizedCallTarget multiTierTarget = (OptimizedCallTarget) new MultiTierWithFrequentCalleeRootNode(calleeTarget, firstTierCompilationThreshold).getCallTarget(); Assert.assertEquals("root:interpreter", multiTierTarget.call()); for (int i = 0; i < firstTierCompilationThreshold - 2; i++) { @@ -275,7 +275,7 @@ public void testLoop() { MultiTierLoopBodyNode body = new MultiTierLoopBodyNode(firstThreshold); final MultiTierWithLoopRootNode rootNode = new MultiTierWithLoopRootNode(body); - OptimizedCallTarget rootTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(rootNode); + OptimizedCallTarget rootTarget = (OptimizedCallTarget) rootNode.getCallTarget(); Assert.assertEquals("break:interpreter", rootTarget.call()); Assert.assertEquals("break:first-tier", rootTarget.call()); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/NodeLimitTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/NodeLimitTest.java index e335eb5b8564..2a233f943dbf 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/NodeLimitTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/NodeLimitTest.java @@ -39,7 +39,6 @@ import org.junit.Test; import com.oracle.truffle.api.RootCallTarget; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.RootNode; @@ -53,7 +52,7 @@ public void before() { } private static OptimizedCallTarget dummyTarget() { - return (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(42)); + return (OptimizedCallTarget) RootNode.createConstantNode(42).getCallTarget(); } @Test @@ -94,7 +93,7 @@ public Integer apply(Integer integer) { }; } }; - partialEval((OptimizedCallTarget) Truffle.getRuntime().createCallTarget(rootNode), new Object[]{}, CompilationIdentifier.INVALID_COMPILATION_ID); + partialEval((OptimizedCallTarget) rootNode.getCallTarget(), new Object[]{}, CompilationIdentifier.INVALID_COMPILATION_ID); } private static class TestRootNode extends RootNode { @@ -141,7 +140,7 @@ private void expectAllOK(Supplier rootNodeFactory) { } private int getBaselineGraphNodeCount(RootNode rootNode) { - final OptimizedCallTarget baselineGraphTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(rootNode); + final OptimizedCallTarget baselineGraphTarget = (OptimizedCallTarget) rootNode.getCallTarget(); final StructuredGraph baselineGraph = partialEval(baselineGraphTarget, new Object[]{}, getCompilationId(baselineGraphTarget)); return baselineGraph.getNodeCount(); } @@ -149,7 +148,7 @@ private int getBaselineGraphNodeCount(RootNode rootNode) { @SuppressWarnings("try") private void peRootNode(int nodeLimit, Supplier rootNodeFactory) { setupContext(Context.newBuilder().allowAllAccess(true).allowExperimentalOptions(true).option("engine.MaximumGraalNodeCount", Integer.toString(nodeLimit)).build()); - RootCallTarget target = Truffle.getRuntime().createCallTarget(rootNodeFactory.get()); + RootCallTarget target = rootNodeFactory.get().getCallTarget(); final Object[] arguments = {1}; partialEval((OptimizedCallTarget) target, arguments, getCompilationId(target)); } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/NodeSplittingStrategyTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/NodeSplittingStrategyTest.java index 3b7960d35118..e1a74b9f3eec 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/NodeSplittingStrategyTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/NodeSplittingStrategyTest.java @@ -24,13 +24,13 @@ */ package org.graalvm.compiler.truffle.test; -import com.oracle.truffle.api.CallTarget; import org.graalvm.compiler.truffle.runtime.OptimizedCallTarget; import org.graalvm.compiler.truffle.runtime.OptimizedDirectCallNode; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.dsl.Cached; @@ -124,7 +124,7 @@ protected static Object doIndirect(RootCallTarget target) { static class TwoDummiesAndAnotherNode extends SplittingTestNode { int counter; - RootCallTarget dummy = runtime.createCallTarget(new DummyRootNode()); + RootCallTarget dummy = new DummyRootNode().getCallTarget(); @Override public Object execute(VirtualFrame frame) { @@ -132,7 +132,7 @@ public Object execute(VirtualFrame frame) { counter++; } else { counter = 0; - dummy = runtime.createCallTarget(new DummyRootNode()); + dummy = new DummyRootNode().getCallTarget(); } return dummy; } @@ -140,26 +140,24 @@ public Object execute(VirtualFrame frame) { @Test public void testSplitsDirectCalls() { - OptimizedCallTarget callTarget = (OptimizedCallTarget) runtime.createCallTarget( - new SplittingTestRootNode(NodeSplittingStrategyTestFactory.HasInlineCacheNodeGen.create(new ReturnsFirstArgumentNode()))); - Object[] first = new Object[]{runtime.createCallTarget(new DummyRootNode())}; - Object[] second = new Object[]{runtime.createCallTarget(new DummyRootNode())}; + OptimizedCallTarget callTarget = (OptimizedCallTarget) new SplittingTestRootNode(NodeSplittingStrategyTestFactory.HasInlineCacheNodeGen.create(new ReturnsFirstArgumentNode())).getCallTarget(); + Object[] first = new Object[]{new DummyRootNode().getCallTarget()}; + Object[] second = new Object[]{new DummyRootNode().getCallTarget()}; testSplitsDirectCallsHelper(callTarget, first, second); - callTarget = (OptimizedCallTarget) runtime.createCallTarget( - new SplittingTestRootNode(NodeSplittingStrategyTestFactory.TurnsPolymorphicOnZeroNodeGen.create(new ReturnsFirstArgumentNode()))); + callTarget = (OptimizedCallTarget) new SplittingTestRootNode(NodeSplittingStrategyTestFactory.TurnsPolymorphicOnZeroNodeGen.create(new ReturnsFirstArgumentNode())).getCallTarget(); // two callers for a target are needed testSplitsDirectCallsHelper(callTarget, new Object[]{1}, new Object[]{0}); } @Test public void testDoesNotSplitsDirectCalls() { - OptimizedCallTarget callTarget = (OptimizedCallTarget) runtime.createCallTarget(new SplittingTestRootNode( - NodeSplittingStrategyTestFactory.TurnsPolymorphicOnZeroButClassIsExcludedNodeGen.create(new ReturnsFirstArgumentNode()))); + OptimizedCallTarget callTarget = (OptimizedCallTarget) new SplittingTestRootNode( + NodeSplittingStrategyTestFactory.TurnsPolymorphicOnZeroButClassIsExcludedNodeGen.create(new ReturnsFirstArgumentNode())).getCallTarget(); testDoesNotSplitDirectCallHelper(callTarget, new Object[]{1}, new Object[]{0}); - callTarget = (OptimizedCallTarget) runtime.createCallTarget(new SplittingTestRootNode( - NodeSplittingStrategyTestFactory.TurnsPolymorphicOnZeroButSpecializationIsExcludedNodeGen.create(new ReturnsFirstArgumentNode()))); + callTarget = (OptimizedCallTarget) new SplittingTestRootNode( + NodeSplittingStrategyTestFactory.TurnsPolymorphicOnZeroButSpecializationIsExcludedNodeGen.create(new ReturnsFirstArgumentNode())).getCallTarget(); testDoesNotSplitDirectCallHelper(callTarget, new Object[]{1}, new Object[]{0}); } @@ -188,19 +186,18 @@ public Object execute(VirtualFrame frame) { @Test public void testSplitPropagatesThrongSoleCallers() { - OptimizedCallTarget turnsPolymorphic = (OptimizedCallTarget) runtime.createCallTarget( - new SplittingTestRootNode(NodeSplittingStrategyTestFactory.TurnsPolymorphicOnZeroNodeGen.create(new ReturnsFirstArgumentNode()))); + OptimizedCallTarget turnsPolymorphic = (OptimizedCallTarget) new SplittingTestRootNode( + NodeSplittingStrategyTestFactory.TurnsPolymorphicOnZeroNodeGen.create(new ReturnsFirstArgumentNode())).getCallTarget(); testPropagatesThroughSoleCallers(turnsPolymorphic, new Object[]{1}, new Object[]{0}); - turnsPolymorphic = (OptimizedCallTarget) runtime.createCallTarget( - new SplittingTestRootNode(NodeSplittingStrategyTestFactory.HasInlineCacheNodeGen.create(new ReturnsFirstArgumentNode()))); - Object[] first = new Object[]{runtime.createCallTarget(new DummyRootNode())}; - Object[] second = new Object[]{runtime.createCallTarget(new DummyRootNode())}; + turnsPolymorphic = (OptimizedCallTarget) new SplittingTestRootNode(NodeSplittingStrategyTestFactory.HasInlineCacheNodeGen.create(new ReturnsFirstArgumentNode())).getCallTarget(); + Object[] first = new Object[]{new DummyRootNode().getCallTarget()}; + Object[] second = new Object[]{new DummyRootNode().getCallTarget()}; testPropagatesThroughSoleCallers(turnsPolymorphic, first, second); } private void testPropagatesThroughSoleCallers(OptimizedCallTarget turnsPolymorphic, Object[] firstArgs, Object[] secondArgs) { - final OptimizedCallTarget callsInner = (OptimizedCallTarget) runtime.createCallTarget(new CallsInnerNode(turnsPolymorphic)); - final OptimizedCallTarget callsCallsInner = (OptimizedCallTarget) runtime.createCallTarget(new CallsInnerNode(callsInner)); + final OptimizedCallTarget callsInner = (OptimizedCallTarget) new CallsInnerNode(turnsPolymorphic).getCallTarget(); + final OptimizedCallTarget callsCallsInner = (OptimizedCallTarget) new CallsInnerNode(callsInner).getCallTarget(); // two callers for a target are needed runtime.createDirectCallNode(callsCallsInner); final DirectCallNode directCallNode = runtime.createDirectCallNode(callsCallsInner); @@ -236,9 +233,9 @@ private void testPropagatesThroughSoleCallers(OptimizedCallTarget turnsPolymorph @Test public void testNoSplitsDirectCallsBecauseFirstExecution() { - final OptimizedCallTarget callTarget = (OptimizedCallTarget) runtime.createCallTarget(new SplittableRootNode() { - @Child private OptimizedDirectCallNode callNode = (OptimizedDirectCallNode) runtime.createDirectCallNode(runtime.createCallTarget( - new SplittingTestRootNode(NodeSplittingStrategyTestFactory.TurnsPolymorphicOnZeroNodeGen.create(new ReturnsFirstArgumentNode())))); + final OptimizedCallTarget callTarget = (OptimizedCallTarget) new SplittableRootNode() { + @Child private OptimizedDirectCallNode callNode = (OptimizedDirectCallNode) runtime.createDirectCallNode( + new SplittingTestRootNode(NodeSplittingStrategyTestFactory.TurnsPolymorphicOnZeroNodeGen.create(new ReturnsFirstArgumentNode())).getCallTarget()); @Override public Object execute(VirtualFrame frame) { @@ -250,7 +247,7 @@ public Object execute(VirtualFrame frame) { callNode.call(second); return null; } - }); + }.getCallTarget(); // Multiple call nodes runtime.createDirectCallNode(callTarget); runtime.createDirectCallNode(callTarget); @@ -262,9 +259,9 @@ public Object execute(VirtualFrame frame) { @Test public void testIncreaseInPolymorphism() { - OptimizedCallTarget callTarget = (OptimizedCallTarget) runtime.createCallTarget( - new SplittingTestRootNode(NodeSplittingStrategyTestFactory.TurnsPolymorphicOnZeroNodeGen.create(new ReturnsFirstArgumentNode()))); - final RootCallTarget outerTarget = runtime.createCallTarget(new CallsInnerNode(callTarget)); + OptimizedCallTarget callTarget = (OptimizedCallTarget) new SplittingTestRootNode( + NodeSplittingStrategyTestFactory.TurnsPolymorphicOnZeroNodeGen.create(new ReturnsFirstArgumentNode())).getCallTarget(); + final RootCallTarget outerTarget = new CallsInnerNode(callTarget).getCallTarget(); Object[] firstArgs = new Object[]{1}; outerTarget.call(firstArgs); Assert.assertFalse("Target needs split before the node went polymorphic", getNeedsSplit(callTarget)); @@ -322,8 +319,7 @@ public Object execute(VirtualFrame frame) { @Test public void testSoloTarget() { final ExposesReportPolymorphicSpecializeRootNode rootNode = new ExposesReportPolymorphicSpecializeRootNode(); - final RootCallTarget callTarget = runtime.createCallTarget(rootNode); - callTarget.call(noArguments); + rootNode.getCallTarget().call(noArguments); rootNode.report(); } @@ -349,10 +345,10 @@ public boolean isCloningAllowed() { @Test public void testSplitsCalledAfterSplit() { final CallableOnlyOnceRootNode rootNode = new CallableOnlyOnceRootNode(); - final RootCallTarget reportsPolymorphism = runtime.createCallTarget(rootNode); + final RootCallTarget reportsPolymorphism = rootNode.getCallTarget(); reportsPolymorphism.call(noArguments); - final RootCallTarget callsInner1 = runtime.createCallTarget(new CallsInnerNode(reportsPolymorphism)); - final RootCallTarget callsInner2 = runtime.createCallTarget(new CallsInnerNode(reportsPolymorphism)); + final RootCallTarget callsInner1 = new CallsInnerNode(reportsPolymorphism).getCallTarget(); + final RootCallTarget callsInner2 = new CallsInnerNode(reportsPolymorphism).getCallTarget(); // make sure the runtime has seen these calls callsInner1.call(noArguments); callsInner2.call(noArguments); @@ -380,8 +376,7 @@ protected static Object doIndirect(int val) { @Test public void testMegamorpic() { - OptimizedCallTarget callTarget = (OptimizedCallTarget) runtime.createCallTarget( - new SplittingTestRootNode(NodeSplittingStrategyTestFactory.MegamorpicNodeGen.create(new ReturnsFirstArgumentNode()))); + OptimizedCallTarget callTarget = (OptimizedCallTarget) new SplittingTestRootNode(NodeSplittingStrategyTestFactory.MegamorpicNodeGen.create(new ReturnsFirstArgumentNode())).getCallTarget(); int[] args = {1, 2, 3, 4, 5}; testMegamorphicHelper(callTarget, args); } @@ -434,8 +429,8 @@ protected static Object doIndirect(int val) { @Test public void testTwoMegamorpicSpec1() { - OptimizedCallTarget callTarget = (OptimizedCallTarget) runtime.createCallTarget( - new SplittingTestRootNode(NodeSplittingStrategyTestFactory.TwoMegamorpicSpecNodeGen.create(new ReturnsFirstArgumentNode()))); + OptimizedCallTarget callTarget = (OptimizedCallTarget) new SplittingTestRootNode( + NodeSplittingStrategyTestFactory.TwoMegamorpicSpecNodeGen.create(new ReturnsFirstArgumentNode())).getCallTarget(); // activates the first spec 2 times than the second (megamorphic) int[] args = {1, 2, 3, 4, 5}; testMegamorphicHelper(callTarget, args); @@ -443,8 +438,8 @@ public void testTwoMegamorpicSpec1() { @Test public void testTwoMegamorpicSpec2() { - OptimizedCallTarget callTarget = (OptimizedCallTarget) runtime.createCallTarget( - new SplittingTestRootNode(NodeSplittingStrategyTestFactory.TwoMegamorpicSpecNodeGen.create(new ReturnsFirstArgumentNode()))); + OptimizedCallTarget callTarget = (OptimizedCallTarget) new SplittingTestRootNode( + NodeSplittingStrategyTestFactory.TwoMegamorpicSpecNodeGen.create(new ReturnsFirstArgumentNode())).getCallTarget(); // activates the first spec 2 times than the last (megamorphic) int[] args = {1, 2, 4, 5, 6}; testMegamorphicHelper(callTarget, args); @@ -467,8 +462,8 @@ protected static Object doIndirect(int val) { @Test public void testPolymorphicInPolyAndMegamorpic() { - OptimizedCallTarget callTarget = (OptimizedCallTarget) runtime.createCallTarget( - new SplittingTestRootNode(NodeSplittingStrategyTestFactory.PolymorphicAndMegamorpicNodeGen.create(new ReturnsFirstArgumentNode()))); + OptimizedCallTarget callTarget = (OptimizedCallTarget) new SplittingTestRootNode( + NodeSplittingStrategyTestFactory.PolymorphicAndMegamorpicNodeGen.create(new ReturnsFirstArgumentNode())).getCallTarget(); // activates the first spec 2 times than the last (megamorphic) int[] args = {1, 2, 3, 4}; final DirectCallNode callNode1 = runtime.createDirectCallNode(callTarget); @@ -492,8 +487,8 @@ public void testPolymorphicInPolyAndMegamorpic() { @Test public void testMegamorphicInPolyAndMegamorpic() { - OptimizedCallTarget callTarget = (OptimizedCallTarget) runtime.createCallTarget( - new SplittingTestRootNode(NodeSplittingStrategyTestFactory.PolymorphicAndMegamorpicNodeGen.create(new ReturnsFirstArgumentNode()))); + OptimizedCallTarget callTarget = (OptimizedCallTarget) new SplittingTestRootNode( + NodeSplittingStrategyTestFactory.PolymorphicAndMegamorpicNodeGen.create(new ReturnsFirstArgumentNode())).getCallTarget(); // activates the first spec 2 times than the last (megamorphic) int[] args = {1, 0, 3, 4}; final DirectCallNode callNode1 = runtime.createDirectCallNode(callTarget); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OSRCancelTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OSRCancelTest.java index c8928519a099..59633b1b2fcf 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OSRCancelTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OSRCancelTest.java @@ -107,7 +107,7 @@ protected Env createContext(Env env) { @Override protected CallTarget parse(ParsingRequest request) throws Exception { - return Truffle.getRuntime().createCallTarget(new RootNode(this) { + return new RootNode(this) { @Child TestInstrumentableNode loop = new TestLoopNode(); @@ -116,7 +116,7 @@ public Object execute(VirtualFrame frame) { loop.execute(frame); return ""; } - }); + }.getCallTarget(); } } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ObjectsRequireNonNullPartialEvaluationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ObjectsRequireNonNullPartialEvaluationTest.java index 61f2e5d846b7..f3c3ca4d4005 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ObjectsRequireNonNullPartialEvaluationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ObjectsRequireNonNullPartialEvaluationTest.java @@ -24,6 +24,8 @@ */ package org.graalvm.compiler.truffle.test; +import java.util.Objects; + import org.graalvm.compiler.truffle.test.ObjectsRequireNonNullPartialEvaluationTest.TestClass.InnerClass; import org.graalvm.compiler.truffle.test.nodes.AbstractTestNode; import org.graalvm.compiler.truffle.test.nodes.RootTestNode; @@ -31,12 +33,8 @@ import org.junit.Test; import com.oracle.truffle.api.RootCallTarget; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.RootNode; - -import java.util.Objects; public class ObjectsRequireNonNullPartialEvaluationTest extends PartialEvaluationTest { @@ -78,8 +76,7 @@ public void testNull() { private void testCommon(AbstractTestNode testNode, String testName, Object arg) { FrameDescriptor fd = new FrameDescriptor(); - RootNode rootNode = new RootTestNode(fd, testName, testNode); - RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode); + RootCallTarget callTarget = new RootTestNode(fd, testName, testNode).getCallTarget(); Assert.assertEquals(42, callTarget.call(arg)); assertPartialEvalNoInvokes(callTarget, new Object[]{arg}); } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OptimizedBlockNodeTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OptimizedBlockNodeTest.java index ec5d8bb04f85..d43fcc3e7886 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OptimizedBlockNodeTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OptimizedBlockNodeTest.java @@ -104,6 +104,38 @@ public void testFirstBlockElementExceedsLimit() { assertEquals(1, target.call()); } + @Test + public void testBoundaryBlockSize() { + /* + * Internal blockRanges and blockSizes arrays grow during partial blocks computation as + * needed. This test tests that the growth of the arrays works correctly. + */ + for (int blockSize = 2; blockSize < 20; blockSize++) { + setup(1); + OptimizedBlockNode block = createBlock(blockSize, 1); + OptimizedCallTarget target = createTest(block); + target.computeBlockCompilations(); + target.call(); + target.compile(true); + + // should not trigger and block compilation + PartialBlocks partialBlocks = block.getPartialBlocks(); + assertNotNull(partialBlocks); + assertNotNull(partialBlocks.getBlockRanges()); + assertEquals(blockSize - 1, partialBlocks.getBlockRanges().length); + for (int i = 0; i < (blockSize - 1); i++) { + assertEquals(i + 1, partialBlocks.getBlockRanges()[i]); + } + assertNotNull(partialBlocks.getBlockTargets()); + assertEquals(blockSize, partialBlocks.getBlockTargets().length); + for (int i = 0; i < blockSize; i++) { + assertTrue(partialBlocks.getBlockTargets()[i].isValid()); + } + + assertEquals(blockSize - 1, target.call()); + } + } + @Test public void testBlockSizePlusOne() { int groupSize = 1; @@ -570,7 +602,7 @@ private static OptimizedBlockNode createBlock(int blockSize, int de private static OptimizedCallTarget createTest(BlockNode block) { TestRootNode root = new TestRootNode(block, "Block[" + block.getElements().length + "]"); - OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(root); + OptimizedCallTarget target = (OptimizedCallTarget) root.getCallTarget(); root.accept(new NodeVisitor() { @Override public boolean visit(Node node) { diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OptimizedCallTargetTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OptimizedCallTargetTest.java index c8dfd0165cbc..d845d3957f9b 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OptimizedCallTargetTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OptimizedCallTargetTest.java @@ -107,7 +107,7 @@ public void testCompilationHeuristics() { testInvalidationCounterCompiled = 0; testInvalidationCounterInterpreted = 0; doInvalidate = false; - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(new RootNode(null) { + OptimizedCallTarget target = (OptimizedCallTarget) new RootNode(null) { @Override public Object execute(VirtualFrame frame) { if (CompilerDirectives.inInterpreter()) { @@ -121,7 +121,7 @@ public Object execute(VirtualFrame frame) { } return null; } - }); + }.getCallTarget(); final int compilationThreshold = target.getOptionValue(PolyglotCompilerOptions.LastTierCompilationThreshold); final int reprofileCount = target.getOptionValue(PolyglotCompilerOptions.ReplaceReprofileCount); assertTrue(compilationThreshold >= 2); @@ -187,7 +187,7 @@ public void testRewriteAssumption() { final int compilationThreshold = 20; setupContext("engine.Inlining", "true", "engine.SingleTierCompilationThreshold", String.valueOf(compilationThreshold), "engine.MultiTier", "false"); - OptimizedCallTarget innermostCallTarget = (OptimizedCallTarget) runtime.createCallTarget(new RootTestNode(new FrameDescriptor(), testName + 0, new AbstractTestNode() { + OptimizedCallTarget innermostCallTarget = (OptimizedCallTarget) new RootTestNode(new FrameDescriptor(), testName + 0, new AbstractTestNode() { @Child private AbstractTestNode child = new ConstantTestNode(42); @Child private AbstractTestNode dummy = new ConstantTestNode(17); @@ -200,12 +200,12 @@ public int execute(VirtualFrame frame) { } return child.execute(frame); } - })); + }).getCallTarget(); assertEquals(compilationThreshold, (int) innermostCallTarget.getOptionValue(PolyglotCompilerOptions.SingleTierCompilationThreshold)); OptimizedCallTarget ct = innermostCallTarget; - ct = (OptimizedCallTarget) runtime.createCallTarget(new RootTestNode(new FrameDescriptor(), testName + 1, new CallTestNode(ct))); - ct = (OptimizedCallTarget) runtime.createCallTarget(new RootTestNode(new FrameDescriptor(), testName + 2, new CallTestNode(ct))); + ct = (OptimizedCallTarget) new RootTestNode(new FrameDescriptor(), testName + 1, new CallTestNode(ct)).getCallTarget(); + ct = (OptimizedCallTarget) new RootTestNode(new FrameDescriptor(), testName + 2, new CallTestNode(ct)).getCallTarget(); final OptimizedCallTarget outermostCallTarget = ct; assertNull("assumption is initially null", getRewriteAssumption(innermostCallTarget)); @@ -264,14 +264,14 @@ public void testCompileOnly1() { // test single include setupContext("engine.CompileOnly", "foobar", "engine.MultiTier", "false"); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(new NamedRootNode("foobar")); + OptimizedCallTarget target = (OptimizedCallTarget) new NamedRootNode("foobar").getCallTarget(); final int compilationThreshold = target.getOptionValue(PolyglotCompilerOptions.SingleTierCompilationThreshold); for (int i = 0; i < compilationThreshold; i++) { assertNotCompiled(target); target.call(); } assertCompiled(target); - target = (OptimizedCallTarget) runtime.createCallTarget(new NamedRootNode("baz")); + target = (OptimizedCallTarget) new NamedRootNode("baz").getCallTarget(); for (int i = 0; i < compilationThreshold; i++) { assertNotCompiled(target); target.call(); @@ -283,14 +283,14 @@ public void testCompileOnly1() { public void testCompileOnly2() { // test single exclude setupContext("engine.CompileOnly", "~foobar", "engine.MultiTier", "false"); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(new NamedRootNode("foobar")); + OptimizedCallTarget target = (OptimizedCallTarget) new NamedRootNode("foobar").getCallTarget(); final int compilationThreshold = target.getOptionValue(PolyglotCompilerOptions.SingleTierCompilationThreshold); for (int i = 0; i < compilationThreshold; i++) { assertNotCompiled(target); target.call(); } assertNotCompiled(target); - target = (OptimizedCallTarget) runtime.createCallTarget(new NamedRootNode("baz")); + target = (OptimizedCallTarget) new NamedRootNode("baz").getCallTarget(); for (int i = 0; i < compilationThreshold; i++) { assertNotCompiled(target); target.call(); @@ -302,14 +302,14 @@ public void testCompileOnly2() { public void testCompileOnly3() { // test two includes/excludes setupContext("engine.CompileOnly", "foo,baz", "engine.MultiTier", "false"); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(new NamedRootNode("foobar")); + OptimizedCallTarget target = (OptimizedCallTarget) new NamedRootNode("foobar").getCallTarget(); final int compilationThreshold = target.getOptionValue(PolyglotCompilerOptions.SingleTierCompilationThreshold); for (int i = 0; i < compilationThreshold; i++) { assertNotCompiled(target); target.call(); } assertCompiled(target); - target = (OptimizedCallTarget) runtime.createCallTarget(new NamedRootNode("baz")); + target = (OptimizedCallTarget) new NamedRootNode("baz").getCallTarget(); for (int i = 0; i < compilationThreshold; i++) { assertNotCompiled(target); target.call(); @@ -336,10 +336,10 @@ public boolean executeRepeating(VirtualFrame frame) { public void testCompileOnly4() { // OSR should not trigger for compile-only includes setupContext("engine.CompileOnly", "foobar"); - OptimizedCallTarget constant = (OptimizedCallTarget) runtime.createCallTarget(RootNode.createConstantNode(42)); + OptimizedCallTarget constant = (OptimizedCallTarget) RootNode.createConstantNode(42).getCallTarget(); final OSRRepeatingNode repeating = new OSRRepeatingNode(constant.getOptionValue(PolyglotCompilerOptions.OSRCompilationThreshold)); final LoopNode loop = runtime.createLoopNode(repeating); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(new NamedRootNode("foobar") { + OptimizedCallTarget target = (OptimizedCallTarget) new NamedRootNode("foobar") { @Child LoopNode loopChild = loop; @@ -349,7 +349,7 @@ public Object execute(VirtualFrame frame) { return super.execute(frame); } - }); + }.getCallTarget(); target.call(); OptimizedCallTarget osrTarget = findOSRTarget(loop); if (osrTarget != null) { @@ -367,7 +367,7 @@ public void testCompilation() { private void testCompilationImpl(Boolean compileOptionValue, boolean expectedCompiled) { String[] options = compileOptionValue == null ? new String[]{"engine.MultiTier", "false"} : new String[]{"engine.Compilation", compileOptionValue.toString(), "engine.MultiTier", "false"}; setupContext(options); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(new NamedRootNode("foobar")); + OptimizedCallTarget target = (OptimizedCallTarget) new NamedRootNode("foobar").getCallTarget(); final int compilationThreshold = target.getOptionValue(PolyglotCompilerOptions.SingleTierCompilationThreshold); for (int i = 0; i < compilationThreshold; i++) { assertNotCompiled(target); @@ -399,10 +399,10 @@ private static OptimizedCallTarget findOSRTarget(Node loopNode) { public void testCompileOnly5() { // OSR should trigger if compile-only with excludes setupContext("engine.CompileOnly", "~foobar"); - OptimizedCallTarget constant = (OptimizedCallTarget) runtime.createCallTarget(RootNode.createConstantNode(42)); + OptimizedCallTarget constant = (OptimizedCallTarget) RootNode.createConstantNode(42).getCallTarget(); final OSRRepeatingNode repeating = new OSRRepeatingNode(constant.getOptionValue(PolyglotCompilerOptions.OSRCompilationThreshold)); final LoopNode loop = runtime.createLoopNode(repeating); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(new NamedRootNode("foobar") { + OptimizedCallTarget target = (OptimizedCallTarget) new NamedRootNode("foobar") { @Child LoopNode loopChild = loop; @@ -412,7 +412,7 @@ public Object execute(VirtualFrame frame) { return super.execute(frame); } - }); + }.getCallTarget(); target.call(); OptimizedCallTarget osrTarget = findOSRTarget(loop); assertCompiled(osrTarget); @@ -430,7 +430,7 @@ public void testInCompilationRootDirective() { int[] innerMethod = {0}; int[] innerBoundary = {0}; - final OptimizedCallTarget innerTarget = (OptimizedCallTarget) runtime.createCallTarget(new RootNode(null) { + final OptimizedCallTarget innerTarget = (OptimizedCallTarget) new RootNode(null) { @Override public String toString() { @@ -462,8 +462,8 @@ void innerBoundary() { innerBoundary[0] = 1; } } - }); - final OptimizedCallTarget outerTarget = (OptimizedCallTarget) runtime.createCallTarget(new RootNode(null) { + }.getCallTarget(); + final OptimizedCallTarget outerTarget = (OptimizedCallTarget) new RootNode(null) { @Override public String toString() { @@ -497,7 +497,7 @@ void outerBoundary() { outerBoundary[0]++; } } - }); + }.getCallTarget(); final int compilationThreshold = outerTarget.getOptionValue(PolyglotCompilerOptions.LastTierCompilationThreshold); for (int i = 0; i < compilationThreshold; i++) { outerTarget.call(); @@ -520,8 +520,8 @@ void outerBoundary() { @Test public void testManyArguments() { setupContext("engine.CompileImmediately", Boolean.TRUE.toString()); - CallTarget fortyTwo = runtime.createCallTarget(new RootTestNode(new FrameDescriptor(), "42", new ConstantTestNode(42))); - OptimizedCallTarget ct = (OptimizedCallTarget) runtime.createCallTarget(new RootTestNode(new FrameDescriptor(), "caller", new CallTestNode(fortyTwo))); + CallTarget fortyTwo = new RootTestNode(new FrameDescriptor(), "42", new ConstantTestNode(42)).getCallTarget(); + OptimizedCallTarget ct = (OptimizedCallTarget) new RootTestNode(new FrameDescriptor(), "caller", new CallTestNode(fortyTwo)).getCallTarget(); for (int i = 0; i < 3; i++) { ct.call(IntStream.range(0, 100000).mapToObj(Integer::valueOf).toArray()); } @@ -533,8 +533,8 @@ public void testNoArgumentTypeSpeculation() { setupContext("engine.CompileImmediately", Boolean.TRUE.toString(), "engine.CompilationFailureAction", "Throw", "engine.BackgroundCompilation", Boolean.FALSE.toString(), "engine.ArgumentTypeSpeculation", Boolean.FALSE.toString()); - CallTarget fortyTwo = runtime.createCallTarget(new RootTestNode(new FrameDescriptor(), "42", new ConstantTestNode(42))); - OptimizedCallTarget ct = (OptimizedCallTarget) runtime.createCallTarget(new RootTestNode(new FrameDescriptor(), "caller", new CallTestNode(fortyTwo))); + CallTarget fortyTwo = new RootTestNode(new FrameDescriptor(), "42", new ConstantTestNode(42)).getCallTarget(); + OptimizedCallTarget ct = (OptimizedCallTarget) new RootTestNode(new FrameDescriptor(), "caller", new CallTestNode(fortyTwo)).getCallTarget(); for (int i = 0; i < 3; i++) { ct.call(IntStream.range(0, 20).mapToObj(Integer::valueOf).toArray()); } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OptimizedOSRLoopNodeTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OptimizedOSRLoopNodeTest.java index 7f34a7a5bcdf..b91c8542f042 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OptimizedOSRLoopNodeTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OptimizedOSRLoopNodeTest.java @@ -87,10 +87,10 @@ public static void doBefore() { // ensure that all classes are properly loaded int defaultThreshold = OSRCompilationThreshold.getDefaultValue(); TestRootNode rootNode = new TestRootNode(defaultThreshold, DEFAULT, new TestRepeatingNode()); - CallTarget target = runtime.createCallTarget(rootNode); + CallTarget target = rootNode.getCallTarget(); target.call(1); rootNode = new TestRootNode(defaultThreshold, CONFIGURED, new TestRepeatingNode()); - target = runtime.createCallTarget(rootNode); + target = rootNode.getCallTarget(); target.call(1); } @@ -98,7 +98,7 @@ public static void doBefore() { @Override public void before() { setupContext("engine.MultiTier", "false"); - OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(0)); + OptimizedCallTarget target = (OptimizedCallTarget) RootNode.createConstantNode(0).getCallTarget(); osrThreshold = target.getOptionValue(OSRCompilationThreshold); } @@ -108,7 +108,7 @@ public void before() { @Theory public void testOSRSingleInvocation(OSRLoopFactory factory) { TestRootNode rootNode = new TestRootNode(osrThreshold, factory, new TestRepeatingNode()); - CallTarget target = runtime.createCallTarget(rootNode); + CallTarget target = rootNode.getCallTarget(); target.call(osrThreshold + 1); assertCompiled(rootNode.getOSRTarget()); target.call(2); @@ -120,7 +120,7 @@ public void testOSRSingleInvocation(OSRLoopFactory factory) { public void testNoInliningForLatency(OSRLoopFactory factory) { setupContext("engine.MultiTier", "false", "engine.Mode", "latency"); TestRootNode rootNode = new TestRootNode(osrThreshold, factory, new CallsTargetRepeatingNode( - (OptimizedDirectCallNode) runtime.createDirectCallNode(runtime.createCallTarget(new RootNode(null) { + (OptimizedDirectCallNode) runtime.createDirectCallNode(new RootNode(null) { @Override public Object execute(VirtualFrame frame) { if (CompilerDirectives.inCompiledCode() && !CompilerDirectives.inCompilationRoot()) { @@ -128,8 +128,8 @@ public Object execute(VirtualFrame frame) { } return 42; } - })))); - CallTarget target = runtime.createCallTarget(rootNode); + }.getCallTarget()))); + CallTarget target = rootNode.getCallTarget(); target.call(osrThreshold + 1); assertCompiled(rootNode.getOSRTarget()); } @@ -139,7 +139,7 @@ public Object execute(VirtualFrame frame) { public void testOSRAndRewriteDoesNotSuppressTargetCompilation(OSRLoopFactory factory) { setupContext("engine.SingleTierCompilationThreshold", "3"); TestRootNodeWithReplacement rootNode = new TestRootNodeWithReplacement(osrThreshold, factory, new TestRepeatingNode()); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); target.call(osrThreshold + 1); assertCompiled(rootNode.getOSRTarget()); assertNotCompiled(target); @@ -175,7 +175,7 @@ public boolean executeRepeating(VirtualFrame frame) { } TestRootNode rootNode = new TestRootNode(osrThreshold, factory, new TransferToInterpreterTestRepeatingNode()); - CallTarget target = runtime.createCallTarget(rootNode); + CallTarget target = rootNode.getCallTarget(); target.call(osrThreshold + 1); try { // Invalidation is asynchronous. @@ -192,7 +192,7 @@ public boolean executeRepeating(VirtualFrame frame) { @Theory public void testNonOSR(OSRLoopFactory factory) { TestRootNode rootNode = new TestRootNode(osrThreshold, factory, new TestRepeatingNode()); - runtime.createCallTarget(rootNode).call(osrThreshold); + rootNode.getCallTarget().call(osrThreshold); assertNotCompiled(rootNode.getOSRTarget()); } @@ -251,7 +251,7 @@ public Object execute(VirtualFrame frame) { @Theory public void testNoInvalidationWithoutFirstExecution(OSRLoopFactory factory) { TestRootNode rootNode = new TestRootNode(osrThreshold, factory, new TestRepeatingNode()); - RootCallTarget target = runtime.createCallTarget(rootNode); + RootCallTarget target = rootNode.getCallTarget(); rootNode.forceOSR(); assertCompiled(rootNode.getOSRTarget()); target.call(1); // should not invalidate OSR @@ -302,7 +302,7 @@ public void testExternalInvalidations(OSRLoopFactory factory) { public void testInternalInvalidations(OSRLoopFactory factory) { TestRepeatingNode repeating = new TestRepeatingNode(); TestRootNode rootNode = new TestRootNode(osrThreshold, factory, repeating); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); target.call(osrThreshold + 1); target.resetCompilationProfile(); assertCompiled(rootNode.getOSRTarget()); @@ -321,7 +321,7 @@ public void testInternalInvalidations(OSRLoopFactory factory) { public void testOuterInvalidationTriggersOSR(OSRLoopFactory factory) { TestRepeatingNode repeating = new TestRepeatingNode(); TestRootNode rootNode = new TestRootNode(osrThreshold, factory, repeating); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); // compile inner target.call(osrThreshold + 1); @@ -366,7 +366,7 @@ public void testOuterInvalidationTriggersOSR(OSRLoopFactory factory) { @Theory public void testNoOSRAfterMinInvocationThreshold(OSRLoopFactory factory) { TestRootNode rootNode = new TestRootNode(osrThreshold, factory, new TestRepeatingNode()); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); int i; for (i = 0; i < target.getOptionValue(MinInvokeThreshold); i++) { target.call(0); @@ -382,7 +382,7 @@ public void testNoOSRAfterMinInvocationThreshold(OSRLoopFactory factory) { @Theory public void testOSRMinInvocationThresholdPropagateLoopCounts(OSRLoopFactory factory) { TestRootNode rootNode = new TestRootNode(osrThreshold, factory, new TestRepeatingNode()); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); int thresholdForOsr = this.osrThreshold; int truffleMinInvokes = target.getOptionValue(MinInvokeThreshold); @@ -429,7 +429,7 @@ public void testThreadSafety(OSRLoopFactory factory) { @Theory public void testTwoLoopsSilblings(OSRLoopFactory factory) { TwoSilblingLoopNodesTest rootNode = new TwoSilblingLoopNodesTest(osrThreshold, factory, new TestRepeatingNode(), new TestRepeatingNode()); - CallTarget target = runtime.createCallTarget(rootNode); + CallTarget target = rootNode.getCallTarget(); target.call(osrThreshold + 1, 1); waitForCompiled(rootNode.getOSRTarget()); waitForCompiled(rootNode.getOSRTarget2()); @@ -474,7 +474,7 @@ public void testTwoLoopsParentChild1(OSRLoopFactory factory) { return null; }); TestRootNode rootNode = new TestRootNode(osrThreshold, factory, childLoop); - CallTarget target = runtime.createCallTarget(rootNode); + CallTarget target = rootNode.getCallTarget(); target.call(1, osrThreshold); assertCompiled(rootNode.getOSRTarget()); @@ -488,7 +488,7 @@ public void testTwoLoopsParentChild2(OSRLoopFactory factory) { return null; }); TestRootNode rootNode = new TestRootNode(osrThreshold, factory, childLoop); - CallTarget target = runtime.createCallTarget(rootNode); + CallTarget target = rootNode.getCallTarget(); target.call(1, osrThreshold + 1); assertCompiled(rootNode.getOSRTarget()); @@ -534,32 +534,32 @@ public boolean executeRepeating(VirtualFrame frame) { @Theory public void testCustomLoopContributingToOSR1(OSRLoopFactory factory) { TestRootNode rootNode = new TestRootNode(osrThreshold, factory, new CustomInnerLoopRepeatingNode()); - runtime.createCallTarget(rootNode).call(10, osrThreshold / 10 - 1); // triggers + rootNode.getCallTarget().call(10, osrThreshold / 10 - 1); // triggers assertNotCompiled(rootNode.getOSRTarget()); - runtime.createCallTarget(rootNode).call(10, osrThreshold / 10); // triggers + rootNode.getCallTarget().call(10, osrThreshold / 10); // triggers assertCompiled(rootNode.getOSRTarget()); } @Theory public void testCustomLoopContributingToOSR2(OSRLoopFactory factory) { TestRootNode rootNode = new TestRootNode(osrThreshold, factory, new CustomInnerLoopRepeatingNode()); - runtime.createCallTarget(rootNode).call(1, osrThreshold - 1); + rootNode.getCallTarget().call(1, osrThreshold - 1); assertNotCompiled(rootNode.getOSRTarget()); - runtime.createCallTarget(rootNode).call(1, osrThreshold); + rootNode.getCallTarget().call(1, osrThreshold); assertCompiled(rootNode.getOSRTarget()); } @Theory public void testCustomLoopContributingToOSR3(OSRLoopFactory factory) { TestRootNode rootNode = new TestRootNode(osrThreshold, factory, new CustomInnerLoopRepeatingNode()); - runtime.createCallTarget(rootNode).call(2, osrThreshold / 2); + rootNode.getCallTarget().call(2, osrThreshold / 2); assertCompiled(rootNode.getOSRTarget()); } @Theory public void testCustomLoopContributingToOSR4(OSRLoopFactory factory) { TestRootNode rootNode = new TestRootNode(osrThreshold, factory, new CustomInnerLoopRepeatingNode()); - runtime.createCallTarget(rootNode).call(2, osrThreshold / 2 - 1); + rootNode.getCallTarget().call(2, osrThreshold / 2 - 1); assertNotCompiled(rootNode.getOSRTarget()); } @@ -592,7 +592,7 @@ public boolean executeRepeating(VirtualFrame frame) { @Theory public void testStackTraceDoesNotShowOSR(OSRLoopFactory factory) { TestRootNode rootNode = new TestRootNode(osrThreshold, factory, new TestOSRStackTrace()); - CallTarget target = runtime.createCallTarget(rootNode); + CallTarget target = rootNode.getCallTarget(); target.call(1); rootNode.forceOSR(); assertCompiled(rootNode.getOSRTarget()); @@ -608,7 +608,7 @@ public void testStackTraceDoesNotShowOSR(OSRLoopFactory factory) { public void testStackFrameNodes(OSRLoopFactory factory) { TestOSRStackTraceFromAbove testOSRStackTrace = new TestOSRStackTraceFromAbove(); TestRootNode rootNode = new TestRootNode(osrThreshold, factory, testOSRStackTrace); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); rootNode.forceOSR(); target.call(1); } @@ -663,7 +663,7 @@ public Object execute(VirtualFrame frame) { return null; } }; - callNode = runtime.createDirectCallNode(runtime.createCallTarget(root)); + callNode = runtime.createDirectCallNode(root.getCallTarget()); adoptChildren(); callNode.call(new Object[]{}); } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OverrideOptionsTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OverrideOptionsTest.java index 9aec32e8fa0c..9bbab932c46b 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OverrideOptionsTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/OverrideOptionsTest.java @@ -33,7 +33,6 @@ import org.junit.Assert; import org.junit.Test; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.nodes.RootNode; public class OverrideOptionsTest extends TruffleCompilerImplTest { @@ -43,7 +42,7 @@ public class OverrideOptionsTest extends TruffleCompilerImplTest { public void testOverrideOptionsUsingContext() { setupContext(Context.newBuilder().allowAllAccess(true).allowExperimentalOptions(true).option("engine.BackgroundCompilation", Boolean.FALSE.toString()).option("engine.CompileImmediately", Boolean.TRUE.toString()).build()); - OptimizedCallTarget callTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(42)); + OptimizedCallTarget callTarget = (OptimizedCallTarget) RootNode.createConstantNode(42).getCallTarget(); OptionValues values = TruffleCompilerImpl.getOptionsForCompiler(GraalTruffleRuntime.getOptionsForCompiler(callTarget)); Assert.assertEquals(false, values.get(PolyglotCompilerOptions.BackgroundCompilation)); Assert.assertEquals(true, values.get(PolyglotCompilerOptions.CompileImmediately)); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/PartialEvaluationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/PartialEvaluationTest.java index 979ed8df577b..106d63a22a00 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/PartialEvaluationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/PartialEvaluationTest.java @@ -54,7 +54,6 @@ import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.RootCallTarget; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ControlFlowException; import com.oracle.truffle.api.nodes.RootNode; @@ -92,7 +91,7 @@ protected final CompilationIdentifier getCompilationId(final RootCallTarget comp } protected OptimizedCallTarget compileHelper(String methodName, RootNode root, Object[] arguments) { - final OptimizedCallTarget compilable = (OptimizedCallTarget) (Truffle.getRuntime()).createCallTarget(root); + final OptimizedCallTarget compilable = (OptimizedCallTarget) root.getCallTarget(); CompilationIdentifier compilationId = getCompilationId(compilable); StructuredGraph graph = partialEval(compilable, arguments, compilationId); this.lastCompilationResult = getTruffleCompiler(compilable).compilePEGraph(graph, methodName, null, compilable, asCompilationRequest(compilationId), null, @@ -120,8 +119,8 @@ protected OptimizedCallTarget assertPartialEvalEquals(RootNode expected, RootNod } protected OptimizedCallTarget assertPartialEvalEquals(RootNode expected, RootNode actual, Object[] arguments, boolean checkConstants) { - final OptimizedCallTarget expectedTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(expected); - final OptimizedCallTarget actualTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(actual); + final OptimizedCallTarget expectedTarget = (OptimizedCallTarget) expected.getCallTarget(); + final OptimizedCallTarget actualTarget = (OptimizedCallTarget) actual.getCallTarget(); BailoutException lastBailout = null; for (int i = 0; i < 10; i++) { @@ -184,8 +183,7 @@ protected void assertPartialEvalNoInvokes(RootNode root) { } protected void assertPartialEvalNoInvokes(RootNode root, Object[] arguments) { - CallTarget callTarget = Truffle.getRuntime().createCallTarget(root); - assertPartialEvalNoInvokes(callTarget, arguments); + assertPartialEvalNoInvokes(root.getCallTarget(), arguments); } protected void assertPartialEvalNoInvokes(CallTarget callTarget, Object[] arguments) { @@ -196,7 +194,7 @@ protected void assertPartialEvalNoInvokes(CallTarget callTarget, Object[] argume } protected StructuredGraph partialEval(RootNode root, Object... arguments) { - OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(root); + OptimizedCallTarget target = (OptimizedCallTarget) root.getCallTarget(); return partialEval(target, arguments); } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/PerformanceWarningTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/PerformanceWarningTest.java index 7dba5e5cac36..957582b08762 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/PerformanceWarningTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/PerformanceWarningTest.java @@ -130,9 +130,8 @@ private void testHelper(RootNode rootNode, boolean expectException, String... ou // Compile and capture output to logger's stream. boolean seenException = false; try { - GraalTruffleRuntime runtime = GraalTruffleRuntime.getRuntime(); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); - DebugContext debug = new Builder(runtime.getGraalOptions(OptionValues.class)).build(); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); + DebugContext debug = new Builder(GraalTruffleRuntime.getRuntime().getGraalOptions(OptionValues.class)).build(); try (DebugCloseable d = debug.disableIntercept(); DebugContext.Scope s = debug.scope("PerformanceWarningTest")) { final OptimizedCallTarget compilable = target; CompilationIdentifier compilationId = getTruffleCompiler(target).createCompilationIdentifier(compilable); @@ -444,13 +443,12 @@ protected class TrivialCallsInnerNode extends RootNode { public TrivialCallsInnerNode() { super(null); - final GraalTruffleRuntime runtime = GraalTruffleRuntime.getRuntime(); - this.callNode = (OptimizedDirectCallNode) runtime.createDirectCallNode(runtime.createCallTarget(new RootNode(null) { + this.callNode = (OptimizedDirectCallNode) GraalTruffleRuntime.getRuntime().createDirectCallNode(new RootNode(null) { @Override public Object execute(VirtualFrame frame) { return 0; } - })); + }.getCallTarget()); } @Override diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/PhiStampInferencePartialEvaluationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/PhiStampInferencePartialEvaluationTest.java index 07f9c201afcb..36beeed03a5a 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/PhiStampInferencePartialEvaluationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/PhiStampInferencePartialEvaluationTest.java @@ -31,7 +31,6 @@ import org.junit.Test; import com.oracle.truffle.api.RootCallTarget; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; @@ -48,7 +47,7 @@ public void ifPhiStamp() { FrameDescriptor fd = new FrameDescriptor(); AbstractTestNode result = new IfPhiStampTestNode(); RootNode rootNode = new RootTestNode(fd, "ifPhiStamp", result); - RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode); + RootCallTarget callTarget = rootNode.getCallTarget(); callTarget.call(new Object[]{true}); callTarget.call(new Object[]{false}); new D().get(); // ensure method cannot be statically bound without receiver type info diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/PolyglotEngineOptionsTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/PolyglotEngineOptionsTest.java index c101fb443c2f..f485882432f9 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/PolyglotEngineOptionsTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/PolyglotEngineOptionsTest.java @@ -33,7 +33,6 @@ import org.junit.Assert; import org.junit.Test; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.sl.runtime.SLContext; import com.oracle.truffle.sl.runtime.SLFunction; @@ -54,7 +53,7 @@ public void testCompilationThreshold() { Assert.assertEquals(2, SLFunction.INLINE_CACHE_SIZE); // doWhile must run isolated and should not affect other compilation thresholds - OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(42)); + OptimizedCallTarget target = (OptimizedCallTarget) RootNode.createConstantNode(42).getCallTarget(); Runnable doWhile = () -> testCompilationThreshold(50, "50", null); testCompilationThreshold(42, "42", doWhile); // test default value testCompilationThreshold(target.getOptionValue(PolyglotCompilerOptions.LastTierCompilationThreshold), null, doWhile); @@ -69,7 +68,7 @@ public void testPolyglotCompilerOptionsAreUsed() { "engine.Inlining", "false", // "engine.Splitting", "false", // "engine.Mode", "latency"); - OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(42)); + OptimizedCallTarget target = (OptimizedCallTarget) RootNode.createConstantNode(42).getCallTarget(); Assert.assertEquals(27, (int) target.getOptionValue(PolyglotCompilerOptions.LastTierCompilationThreshold)); Assert.assertEquals(true, target.getOptionValue(PolyglotCompilerOptions.TraceCompilation)); Assert.assertEquals(true, target.getOptionValue(PolyglotCompilerOptions.TraceCompilationDetails)); @@ -83,7 +82,7 @@ public void testEngineModeLatency() { Assert.assertEquals(OptionStability.STABLE, Engine.create().getOptions().get("engine.Mode").getStability()); setupContext("engine.Mode", "latency"); - OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(42)); + OptimizedCallTarget target = (OptimizedCallTarget) RootNode.createConstantNode(42).getCallTarget(); Assert.assertEquals(PolyglotCompilerOptions.EngineModeEnum.LATENCY, target.getOptionValue(PolyglotCompilerOptions.Mode)); Assert.assertEquals(true, target.engine.inlining); Assert.assertEquals(false, target.engine.splitting); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/RewriteDuringCompilationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/RewriteDuringCompilationTest.java index 8300eef3a54d..c047c8935d72 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/RewriteDuringCompilationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/RewriteDuringCompilationTest.java @@ -221,7 +221,7 @@ private void testCompilation(BaseNode testedCode, LoopNode loopNode, DetectInval protected synchronized CallTarget parse(ParsingRequest request) throws Exception { com.oracle.truffle.api.source.Source source = request.getSource(); if (target == null) { - target = Truffle.getRuntime().createCallTarget(new RootNode(languageInstance) { + target = new RootNode(languageInstance) { @Node.Child private volatile BaseNode child = testedCode; @@ -235,7 +235,7 @@ public SourceSection getSourceSection() { return source.createSection(1); } - }); + }.getCallTarget(); } return target; } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/SimplePartialEvaluationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/SimplePartialEvaluationTest.java index 72a9ecce3660..78d0f7644e1b 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/SimplePartialEvaluationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/SimplePartialEvaluationTest.java @@ -225,8 +225,8 @@ public void unrollUntilReturnNestedLoopsContinueOuter01() { FrameDescriptor fd = new FrameDescriptor(); final int loopIterations = 2; UnrollingTestNode t = new UnrollingTestNode(loopIterations); - AbstractTestNode result = new AddTestNode(t.new FullUnrollUntilReturnNestedLoopsContinueOuter01(), new ConstantTestNode(37)); - compileHelper("Test", new RootTestNode(fd, "nestedLoopExplosion", result), new Object[]{}); + AbstractTestNode result = new AddTestNode(t.new FullUnrollUntilReturnNestedLoopsContinueOuter01(), new ConstantTestNode(37), true); + compileHelper("Test", new RootTestNode(fd, "nestedLoopExplosion", result, true), new Object[]{}); StructuredGraph peResult = lastCompiledGraph; Assert.assertEquals(UnrollingTestNode.INSIDE_LOOP_MARKER, 4, UnrollingTestNode.countBlackholeNodes(peResult, UnrollingTestNode.INSIDE_LOOP_MARKER)); @@ -238,8 +238,8 @@ public void unrollUntilReturnNestedLoopsContinueOuter02() { FrameDescriptor fd = new FrameDescriptor(); final int loopIterations = 2; UnrollingTestNode t = new UnrollingTestNode(loopIterations); - AbstractTestNode result = new AddTestNode(t.new FullUnrollUntilReturnNestedLoopsContinueOuter02(), new ConstantTestNode(37)); - compileHelper("Test", new RootTestNode(fd, "nestedLoopExplosion", result), new Object[]{}); + AbstractTestNode result = new AddTestNode(t.new FullUnrollUntilReturnNestedLoopsContinueOuter02(), new ConstantTestNode(37), true); + compileHelper("Test", new RootTestNode(fd, "nestedLoopExplosion", result, true), new Object[]{}); StructuredGraph peResult = lastCompiledGraph; Assert.assertEquals(UnrollingTestNode.INSIDE_LOOP_MARKER, 8, UnrollingTestNode.countBlackholeNodes(peResult, UnrollingTestNode.INSIDE_LOOP_MARKER)); @@ -251,8 +251,8 @@ public void unrollUntilReturnNestedLoopsContinueOuter03() { FrameDescriptor fd = new FrameDescriptor(); final int loopIterations = 2; UnrollingTestNode t = new UnrollingTestNode(loopIterations); - AbstractTestNode result = new AddTestNode(t.new FullUnrollUntilReturnNestedLoopsContinueOuter03(), new ConstantTestNode(37)); - compileHelper("Test", new RootTestNode(fd, "nestedLoopExplosion", result), new Object[]{}); + AbstractTestNode result = new AddTestNode(t.new FullUnrollUntilReturnNestedLoopsContinueOuter03(), new ConstantTestNode(37), true); + compileHelper("Test", new RootTestNode(fd, "nestedLoopExplosion", result, true), new Object[]{}); StructuredGraph peResult = lastCompiledGraph; Assert.assertEquals(UnrollingTestNode.INSIDE_LOOP_MARKER, 4, UnrollingTestNode.countBlackholeNodes(peResult, UnrollingTestNode.INSIDE_LOOP_MARKER)); @@ -264,8 +264,8 @@ public void unrollUntilReturnNestedLoopsContinueOuter04() { FrameDescriptor fd = new FrameDescriptor(); final int loopIterations = 2; UnrollingTestNode t = new UnrollingTestNode(loopIterations); - AbstractTestNode result = new AddTestNode(t.new FullUnrollUntilReturnNestedLoopsContinueOuter04(), new ConstantTestNode(37)); - compileHelper("Test", new RootTestNode(fd, "nestedLoopExplosion", result), new Object[]{}); + AbstractTestNode result = new AddTestNode(t.new FullUnrollUntilReturnNestedLoopsContinueOuter04(), new ConstantTestNode(37), true); + compileHelper("Test", new RootTestNode(fd, "nestedLoopExplosion", result, true), new Object[]{}); StructuredGraph peResult = lastCompiledGraph; Assert.assertEquals(UnrollingTestNode.INSIDE_LOOP_MARKER, 4, UnrollingTestNode.countBlackholeNodes(peResult, UnrollingTestNode.INSIDE_LOOP_MARKER)); @@ -277,8 +277,8 @@ public void unrollUntilReturnNestedLoopsContinueOuter05() { FrameDescriptor fd = new FrameDescriptor(); final int loopIterations = 2; UnrollingTestNode t = new UnrollingTestNode(loopIterations); - AbstractTestNode result = new AddTestNode(t.new FullUnrollUntilReturnNestedLoopsContinueOuter05(), new ConstantTestNode(37)); - compileHelper("Test", new RootTestNode(fd, "nestedLoopExplosion", result), new Object[]{}); + AbstractTestNode result = new AddTestNode(t.new FullUnrollUntilReturnNestedLoopsContinueOuter05(), new ConstantTestNode(37), true); + compileHelper("Test", new RootTestNode(fd, "nestedLoopExplosion", result, true), new Object[]{}); StructuredGraph peResult = lastCompiledGraph; Assert.assertEquals(UnrollingTestNode.INSIDE_LOOP_MARKER, 6, UnrollingTestNode.countBlackholeNodes(peResult, UnrollingTestNode.INSIDE_LOOP_MARKER)); @@ -458,7 +458,7 @@ public void complexUnrollFullUnrollUntilReturn() { final int loopIterations = 5; UnrollingTestNode t = new UnrollingTestNode(loopIterations); AbstractTestNode result = new AddTestNode(t.new Unroll01(), new ConstantTestNode(37)); - compileHelper("Test", new RootTestNode(fd, "nestedLoopExplosion", result), new Object[]{}); + compileHelper("Test", new RootTestNode(fd, "nestedLoopExplosion", result, true), new Object[]{}); StructuredGraph peResult = lastCompiledGraph; //@formatter:off /* @@ -499,7 +499,7 @@ public void complexUnrollFullExplodeUntilReturn() throws Exception { final int loopIterations = 5; UnrollingTestNode t = new UnrollingTestNode(loopIterations); AbstractTestNode result = new AddTestNode(t.new Unroll02(), new ConstantTestNode(37)); - compileHelper("Test", new RootTestNode(fd, "nestedLoopExplosion", result), new Object[]{}); + compileHelper("Test", new RootTestNode(fd, "nestedLoopExplosion", result, true), new Object[]{}); StructuredGraph peResult = lastCompiledGraph; //@formatter:off diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ThreadsActivationCompilationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ThreadsActivationCompilationTest.java index eedef1736e4b..c50416c0c9ee 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ThreadsActivationCompilationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/ThreadsActivationCompilationTest.java @@ -83,7 +83,7 @@ public void onEnterThread(TruffleContext c) { compiledEnter.set(Boolean.FALSE); compiledLeave.set(Boolean.FALSE); - OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(new RootNode(null) { + OptimizedCallTarget target = (OptimizedCallTarget) new RootNode(null) { @Override public Object execute(VirtualFrame frame) { TruffleContext tc = (TruffleContext) frame.getArguments()[0]; @@ -104,7 +104,7 @@ public Object execute(VirtualFrame frame) { } return null; } - }); + }.getCallTarget(); TruffleContext tc = LanguageContext.get(null).getEnv().getContext(); singleContext.invalidate(); target.call(tc); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TraceCompilationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TraceCompilationTest.java index 11073a2a1eb8..b1b700712501 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TraceCompilationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TraceCompilationTest.java @@ -24,11 +24,6 @@ */ package org.graalvm.compiler.truffle.test; -import com.oracle.truffle.api.Assumption; -import com.oracle.truffle.api.Truffle; -import com.oracle.truffle.api.frame.FrameDescriptor; -import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.RootNode; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; @@ -47,6 +42,7 @@ import java.util.logging.LogRecord; import java.util.regex.Pattern; import java.util.stream.Collectors; + import org.graalvm.compiler.test.SubprocessUtil; import org.graalvm.compiler.truffle.runtime.OptimizedCallTarget; import org.graalvm.compiler.truffle.test.nodes.AbstractTestNode; @@ -55,6 +51,12 @@ import org.junit.Assert; import org.junit.Test; +import com.oracle.truffle.api.Assumption; +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.RootNode; + public class TraceCompilationTest extends TestWithPolyglotOptions { private static final String CONFIGURED_PROPERTY = ExceptionActionTest.class.getSimpleName() + ".configured"; @@ -130,7 +132,7 @@ public void testNoEngineTracingOn() throws Exception { PrintStream origSystemErr = System.err; ByteArrayOutputStream rawStdErr = new ByteArrayOutputStream(); System.setErr(new PrintStream(rawStdErr, true, "UTF-8")); - OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(10)); + OptimizedCallTarget target = (OptimizedCallTarget) RootNode.createConstantNode(10).getCallTarget(); target.call(); System.setErr(origSystemErr); String strStdErr = rawStdErr.toString("UTF-8"); @@ -249,10 +251,10 @@ private void testHelper(Supplier rootProvider, Map add } TestHandler handler = builder.build(); setupContext(newContextBuilder(additionalOptions, handler)); - OptimizedCallTarget warmUpTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(rootProvider.get()); + OptimizedCallTarget warmUpTarget = (OptimizedCallTarget) rootProvider.get().getCallTarget(); warmUpTarget.call(); handler.start(); - OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(rootProvider.get()); + OptimizedCallTarget target = (OptimizedCallTarget) rootProvider.get().getCallTarget(); target.call(); handler.assertLogs(); return null; diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TransferToInterpreterTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TransferToInterpreterTest.java index 43de7e5ab98a..9901472094a1 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TransferToInterpreterTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TransferToInterpreterTest.java @@ -53,7 +53,7 @@ public void setup() { public void test() { RootNode rootNode = new TestRootNode(); GraalTruffleRuntime runtime = GraalTruffleRuntime.getRuntime(); - OptimizedCallTarget target = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + OptimizedCallTarget target = (OptimizedCallTarget) rootNode.getCallTarget(); target.call(0); Assert.assertFalse(target.isValid()); final OptimizedCallTarget compilable = target; diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleBoundaryExceptionsTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleBoundaryExceptionsTest.java index 1bc7432aa743..f8737f74a231 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleBoundaryExceptionsTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleBoundaryExceptionsTest.java @@ -28,6 +28,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import org.graalvm.compiler.truffle.common.TruffleCompilationTask; import org.graalvm.compiler.truffle.options.PolyglotCompilerOptions; import org.graalvm.compiler.truffle.runtime.GraalTruffleRuntime; import org.graalvm.compiler.truffle.runtime.GraalTruffleRuntimeListener; @@ -88,14 +89,14 @@ public void throwExceptionBoundary() { final int[] compilationCount = {0}; GraalTruffleRuntimeListener listener = new GraalTruffleRuntimeListener() { @Override - public void onCompilationStarted(OptimizedCallTarget target, int tier) { + public void onCompilationStarted(OptimizedCallTarget target, TruffleCompilationTask task) { compilationCount[0]++; } }; setupContext("engine.InvalidationReprofileCount", "0", "engine.MultiTier", "false"); DeoptCountingExceptionOverBoundaryRootNode rootNode = new DeoptCountingExceptionOverBoundaryRootNode(); - final OptimizedCallTarget outerTarget = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + final OptimizedCallTarget outerTarget = (OptimizedCallTarget) rootNode.getCallTarget(); final int compilationThreshold = outerTarget.getOptionValue(SingleTierCompilationThreshold); for (int i = 0; i < compilationThreshold; i++) { @@ -159,7 +160,7 @@ public void throwExceptionBoundary() { } DeoptCountingExceptionOverBoundaryRootNode rootNode = new DeoptCountingExceptionOverBoundaryRootNode(); - final OptimizedCallTarget outerTarget = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + final OptimizedCallTarget outerTarget = (OptimizedCallTarget) rootNode.getCallTarget(); final int compilationThreshold = outerTarget.getOptionValue(PolyglotCompilerOptions.SingleTierCompilationThreshold); for (int i = 0; i < compilationThreshold; i++) { outerTarget.call(); @@ -208,7 +209,7 @@ public void throwExceptionBoundary() { } DeoptCountingExceptionOverBoundaryRootNode rootNode = new DeoptCountingExceptionOverBoundaryRootNode(); - final OptimizedCallTarget outerTarget = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + final OptimizedCallTarget outerTarget = (OptimizedCallTarget) rootNode.getCallTarget(); final int compilationThreshold = outerTarget.getOptionValue(PolyglotCompilerOptions.SingleTierCompilationThreshold); final int invalidationReprofileCount = outerTarget.getOptionValue(PolyglotCompilerOptions.InvalidationReprofileCount); @@ -278,7 +279,7 @@ public void throwExceptionBoundary() { } DeoptCountingExceptionOverBoundaryRootNode rootNode = new DeoptCountingExceptionOverBoundaryRootNode(); - final OptimizedCallTarget outerTarget = (OptimizedCallTarget) runtime.createCallTarget(rootNode); + final OptimizedCallTarget outerTarget = (OptimizedCallTarget) rootNode.getCallTarget(); final int compilationThreshold = outerTarget.getOptionValue(PolyglotCompilerOptions.SingleTierCompilationThreshold); for (int i = 0; i < compilationThreshold; i++) { try { diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleBoundaryInliningTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleBoundaryInliningTest.java index bbc694251992..05b207125e46 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleBoundaryInliningTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleBoundaryInliningTest.java @@ -34,17 +34,10 @@ import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.RootCallTarget; -import com.oracle.truffle.api.Truffle; -import com.oracle.truffle.api.TruffleRuntime; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.RootNode; public class TruffleBoundaryInliningTest extends PartialEvaluationTest { - private TruffleRuntime runtime; - - public TruffleBoundaryInliningTest() { - this.runtime = Truffle.getRuntime(); - } private static RootNode createRootNodeAllowInline() { return new RootNode(null) { @@ -78,10 +71,10 @@ void testMethod() { private void runTest() { RootNode n1 = createRootNodeAllowInline(); - RootCallTarget c1 = runtime.createCallTarget(n1); + RootCallTarget c1 = n1.getCallTarget(); StructuredGraph allowInline = partialEval((OptimizedCallTarget) c1, new Object[]{}, getCompilationId(c1)); RootNode n2 = createRootNodeNoInline(); - RootCallTarget c2 = runtime.createCallTarget(n2); + RootCallTarget c2 = n2.getCallTarget(); StructuredGraph noInline = partialEval((OptimizedCallTarget) c2, new Object[]{}, getCompilationId(c2)); checkHasTestMethod(allowInline); checkHasTestMethod(noInline); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleCompilerImplTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleCompilerImplTest.java index e4649441b876..d5e6354a9901 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleCompilerImplTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleCompilerImplTest.java @@ -37,7 +37,6 @@ import org.junit.Assume; import org.junit.Before; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleOptions; import com.oracle.truffle.api.nodes.RootNode; @@ -59,8 +58,7 @@ protected TruffleCompilerImplTest() { @Before public void onlyWhiteBox() { if (TruffleOptions.AOT) { - GraalTruffleRuntime runtime = GraalTruffleRuntime.getRuntime(); - TruffleCompiler compiler = runtime.getTruffleCompiler((OptimizedCallTarget) runtime.createCallTarget(RootNode.createConstantNode(42))); + TruffleCompiler compiler = GraalTruffleRuntime.getRuntime().getTruffleCompiler((OptimizedCallTarget) RootNode.createConstantNode(42).getCallTarget()); Assume.assumeTrue("cannot get whitebox interface to Truffle compiler", compiler instanceof TruffleCompilerImpl); this.truffleCompiler = (TruffleCompilerImpl) compiler; } @@ -75,7 +73,7 @@ protected final TruffleCompilerImpl getTruffleCompiler(OptimizedCallTarget callT @Override protected CompilationIdentifier createCompilationId() { - OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(42)); + OptimizedCallTarget target = (OptimizedCallTarget) RootNode.createConstantNode(42).getCallTarget(); return getTruffleCompiler(target).createCompilationIdentifier(target); } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleContextCompilationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleContextCompilationTest.java index 97d4b07f8974..35f9ccdf4d1b 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleContextCompilationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleContextCompilationTest.java @@ -56,27 +56,31 @@ public void testInnerContextsDeoptimize() { Env env = Language.REFERENCE.get(null); TruffleContext context = env.newContextBuilder().build(); - OptimizedCallTarget target = assertCompiling(new RootNode(null) { - @Override - public Object execute(VirtualFrame frame) { - Object prev = context.enter(this); - try { - // barrier ensures that the deopt does not move up or downwards - barrier(); - Object arg = frame.getArguments()[0]; - if (arg != FIRST_RUN) { - CompilerDirectives.transferToInterpreterAndInvalidate(); + try { + OptimizedCallTarget target = assertCompiling(new RootNode(null) { + @Override + public Object execute(VirtualFrame frame) { + Object prev = context.enter(this); + try { + // barrier ensures that the deopt does not move up or downwards + barrier(); + Object arg = frame.getArguments()[0]; + if (arg != FIRST_RUN) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + } + barrier(); + } finally { + context.leave(this, prev); } - barrier(); - } finally { - context.leave(this, prev); + return null; } - return null; - } - }); - assertTrue(target.isValid()); - target.call(new Object()); - assertFalse(target.isValid()); + }); + assertTrue(target.isValid()); + target.call(new Object()); + assertFalse(target.isValid()); + } finally { + context.close(); + } } private OptimizedCallTarget assertCompiling(RootNode node) { diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleDirectCallNodeTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleDirectCallNodeTest.java index 0bde080447b0..09d82acfb3fc 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleDirectCallNodeTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleDirectCallNodeTest.java @@ -49,7 +49,7 @@ public boolean isCloningAllowed() { return true; } }; - final CallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode); + final CallTarget callTarget = rootNode.getCallTarget(); final DirectCallNode callNode = Truffle.getRuntime().createDirectCallNode(callTarget); assertTrue(callNode.isCallTargetCloningAllowed()); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleExceptionPartialEvaluationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleExceptionPartialEvaluationTest.java index a55b440f0ba1..e912b979dfa6 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleExceptionPartialEvaluationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleExceptionPartialEvaluationTest.java @@ -78,14 +78,14 @@ static RootTestNode createCallerChain(int framesAbove, int framesBelow, NodeFact AbstractTestNode calleeNode = factory.createThrowNode(-1, true); RootTestNode calleeRoot = new RootTestNode(fd, "testTruffleException", calleeNode); for (int i = 0; i < framesAbove; i++) { - AbstractTestNode call = new CallTestNode(Truffle.getRuntime().createCallTarget(calleeRoot)); + AbstractTestNode call = new CallTestNode(calleeRoot.getCallTarget()); calleeRoot = new RootTestNode(fd, "testTruffleException", call); } - AbstractTestNode callerNode = new CallTestNode(Truffle.getRuntime().createCallTarget(calleeRoot)); + AbstractTestNode callerNode = new CallTestNode(calleeRoot.getCallTarget()); AbstractTestNode catchNode = factory.createCatchNode(callerNode); RootTestNode callerRoot = new RootTestNode(fd, "testTruffleException", catchNode); for (int i = 0; i < framesBelow; i++) { - AbstractTestNode call = new CallTestNode(Truffle.getRuntime().createCallTarget(callerRoot)); + AbstractTestNode call = new CallTestNode(callerRoot.getCallTarget()); callerRoot = new RootTestNode(fd, "testTruffleException", call); } return callerRoot; diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleReturnBoxedParameterTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleReturnBoxedParameterTest.java index 81e2a11d4a27..21edbeb5be44 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleReturnBoxedParameterTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleReturnBoxedParameterTest.java @@ -30,7 +30,6 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.extended.ForeignCallNode; -import org.graalvm.compiler.truffle.runtime.GraalTruffleRuntime; import org.graalvm.compiler.truffle.runtime.OptimizedCallTarget; import org.graalvm.compiler.truffle.test.TruffleReturnBoxedParameterTestFactory.IntNodeFactory; import org.junit.Test; @@ -142,7 +141,7 @@ static E createNode(NodeFactory factory, boolean prefixCons @Test public void testBox() throws Throwable { TestRootNode node = createRoot(IntNodeFactory.getInstance()); - OptimizedCallTarget callTarget = (OptimizedCallTarget) GraalTruffleRuntime.getRuntime().createCallTarget(node); + OptimizedCallTarget callTarget = (OptimizedCallTarget) node.getCallTarget(); StructuredGraph g = partialEval(callTarget, new Object[]{1}); compile(callTarget, g); // no box foreign call to allocation snippet after box optimization diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleToTruffleCallExceptionHandlerTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleToTruffleCallExceptionHandlerTest.java index 3a37bd9050cf..8b67c1b2d5c4 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleToTruffleCallExceptionHandlerTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/TruffleToTruffleCallExceptionHandlerTest.java @@ -47,7 +47,7 @@ public class TruffleToTruffleCallExceptionHandlerTest extends PartialEvaluationT private static final class Compilables { - final OptimizedCallTarget calleeNoException = (OptimizedCallTarget) GraalTruffleRuntime.getRuntime().createCallTarget(new RootNode(null) { + final OptimizedCallTarget calleeNoException = (OptimizedCallTarget) new RootNode(null) { @Override public Object execute(VirtualFrame frame) { return null; @@ -57,9 +57,9 @@ public Object execute(VirtualFrame frame) { public String toString() { return "CALLEE_NO_EXCEPTION"; } - }); + }.getCallTarget(); - final OptimizedCallTarget callerNoException = (OptimizedCallTarget) runtime.createCallTarget(new RootNode(null) { + final OptimizedCallTarget callerNoException = (OptimizedCallTarget) new RootNode(null) { @Child protected DirectCallNode callNode = runtime.createDirectCallNode(calleeNoException); @@ -73,9 +73,9 @@ public Object execute(VirtualFrame frame) { public String toString() { return "CALLER_NO_EXCEPTION"; } - }); + }.getCallTarget(); - final OptimizedCallTarget calleeWithException = (OptimizedCallTarget) runtime.createCallTarget(new RootNode(null) { + final OptimizedCallTarget calleeWithException = (OptimizedCallTarget) new RootNode(null) { @Override public Object execute(VirtualFrame frame) { throw new RuntimeException(); @@ -85,9 +85,9 @@ public Object execute(VirtualFrame frame) { public String toString() { return "CALLEE_EXCEPTION"; } - }); + }.getCallTarget(); - final OptimizedCallTarget callerWithException = (OptimizedCallTarget) runtime.createCallTarget(new RootNode(null) { + final OptimizedCallTarget callerWithException = (OptimizedCallTarget) new RootNode(null) { @Child protected DirectCallNode callNode = runtime.createDirectCallNode(calleeWithException); @@ -101,7 +101,7 @@ public Object execute(VirtualFrame frame) { public String toString() { return "CALLER_EXCEPTION"; } - }); + }.getCallTarget(); } @Test diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/UnrollLoopBlockDuplicationTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/UnrollLoopBlockDuplicationTest.java index 2b890f7faba4..91508729a46f 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/UnrollLoopBlockDuplicationTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/UnrollLoopBlockDuplicationTest.java @@ -29,7 +29,6 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.dsl.UnsupportedSpecializationException; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; @@ -45,7 +44,7 @@ public class UnrollLoopBlockDuplicationTest extends TestWithSynchronousCompiling */ @Test public void testBlockDuplication() { - OptimizedCallTarget target = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(new ObjectCacheTestRootNode()); + OptimizedCallTarget target = (OptimizedCallTarget) new ObjectCacheTestRootNode().getCallTarget(); AbstractType value1 = new ConcreteType1(); AbstractType value2 = new ConcreteType2(); target.call(value1); diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/inlining/InlineOnlyTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/inlining/InlineOnlyTest.java index 04e1a4042688..007d7fd36fbd 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/inlining/InlineOnlyTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/inlining/InlineOnlyTest.java @@ -34,7 +34,6 @@ import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleLanguage; -import com.oracle.truffle.api.TruffleRuntime; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.RootNode; @@ -80,8 +79,7 @@ public static class ExcludePatternTestLanguage extends ProxyLanguage { @Override protected CallTarget parse(ParsingRequest request) throws Exception { - final TruffleRuntime runtime = Truffle.getRuntime(); - final RootCallTarget rootCallTarget = runtime.createCallTarget(new RootNode(this) { + final RootCallTarget rootCallTarget = new RootNode(this) { @Override public String toString() { @@ -98,10 +96,10 @@ public Object execute(VirtualFrame frame) { public String getName() { return METHOD_EXCLUDED_FROM_INLINING; } - }); - return runtime.createCallTarget(new RootNode(this) { + }.getCallTarget(); + return new RootNode(this) { - @Child DirectCallNode callNode = runtime.createDirectCallNode(rootCallTarget); + @Child DirectCallNode callNode = Truffle.getRuntime().createDirectCallNode(rootCallTarget); @Override public String toString() { @@ -117,7 +115,7 @@ public String getName() { public Object execute(VirtualFrame frame) { return callNode.call(); } - }); + }.getCallTarget(); } } @@ -128,8 +126,7 @@ public static class InlineSelectedMethodsTestLanguage extends ProxyLanguage { @Override protected CallTarget parse(ParsingRequest request) throws Exception { - final TruffleRuntime runtime = Truffle.getRuntime(); - final RootCallTarget rootCallTarget = runtime.createCallTarget(new RootNode(this) { + final RootCallTarget rootCallTarget = new RootNode(this) { @Override public String toString() { @@ -153,10 +150,10 @@ private void assertFalse(boolean inCompilationRoot) { public String getName() { return METHOD_INLINED; } - }); - return runtime.createCallTarget(new RootNode(this) { + }.getCallTarget(); + return new RootNode(this) { - @Child DirectCallNode callNode = runtime.createDirectCallNode(rootCallTarget); + @Child DirectCallNode callNode = Truffle.getRuntime().createDirectCallNode(rootCallTarget); @Override public String toString() { @@ -172,7 +169,7 @@ public String getName() { public Object execute(VirtualFrame frame) { return callNode.call(); } - }); + }.getCallTarget(); } } } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/inlining/InliningTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/inlining/InliningTest.java index f8269c684480..f4cfe1d567f7 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/inlining/InliningTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/inlining/InliningTest.java @@ -32,7 +32,6 @@ import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleLanguage; -import com.oracle.truffle.api.TruffleRuntime; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.RootNode; @@ -71,8 +70,7 @@ public static class InliningTestLanguage extends ProxyLanguage { @Override protected CallTarget parse(ParsingRequest request) throws Exception { - final TruffleRuntime runtime = Truffle.getRuntime(); - final RootCallTarget mustNotInline = runtime.createCallTarget(new RootNode(this) { + final RootCallTarget mustNotInline = new RootNode(this) { @Override public String toString() { @@ -84,10 +82,10 @@ public Object execute(VirtualFrame frame) { CompilerDirectives.bailout("This node should not be inlined"); return 42; } - }); - return runtime.createCallTarget(new RootNode(this) { + }.getCallTarget(); + return new RootNode(this) { - @Child DirectCallNode callNode = runtime.createDirectCallNode(mustNotInline); + @Child DirectCallNode callNode = Truffle.getRuntime().createDirectCallNode(mustNotInline); @Override public String toString() { @@ -103,7 +101,7 @@ public String getName() { public Object execute(VirtualFrame frame) { return callNode.call(); } - }); + }.getCallTarget(); } } } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/libgraal/JNIExceptionWrapperTest.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/libgraal/JNIExceptionWrapperTest.java index 2a9429f5a632..40bba5eecd1d 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/libgraal/JNIExceptionWrapperTest.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/libgraal/JNIExceptionWrapperTest.java @@ -90,7 +90,7 @@ private static List makeSilent(List vmArgs) { private void testMergedStackTraceImpl() throws Exception { setupContext("engine.CompilationExceptionsAreThrown", Boolean.TRUE.toString(), "engine.CompilationExceptionsAreFatal", Boolean.FALSE.toString()); GraalTruffleRuntime runtime = GraalTruffleRuntime.getRuntime(); - OptimizedCallTarget compilable = (OptimizedCallTarget) runtime.createCallTarget(RootNode.createConstantNode(42)); + OptimizedCallTarget compilable = (OptimizedCallTarget) RootNode.createConstantNode(42).getCallTarget(); TruffleCompiler compiler = runtime.getTruffleCompiler(compilable); try (TruffleCompilation compilation = compiler.openCompilation(compilable)) { try (TruffleDebugContext debug = compiler.openDebugContext(GraalTruffleRuntime.getOptionsForCompiler(compilable), compilation)) { @@ -139,10 +139,6 @@ public void onSuccess(CompilableTruffleAST compilable, TruffleInliningData inlin @Override public void onFailure(CompilableTruffleAST compilable, String reason, boolean bailout, boolean permanentBailout, int tier) { } - - @Override - public void onCompilationRetry(CompilableTruffleAST compilable, int tier) { - } } private static class TestTruffleCompilationTask implements TruffleCompilationTask { diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/nodes/AddTestNode.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/nodes/AddTestNode.java index f2adf0c8001f..5ac71ed93ed8 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/nodes/AddTestNode.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/nodes/AddTestNode.java @@ -24,20 +24,32 @@ */ package org.graalvm.compiler.truffle.test.nodes; +import org.graalvm.compiler.api.directives.GraalDirectives; + import com.oracle.truffle.api.frame.VirtualFrame; public class AddTestNode extends AbstractTestNode { @Child private AbstractTestNode left; @Child private AbstractTestNode right; + private final boolean cfgAnchorBeforeReturn; - public AddTestNode(AbstractTestNode left, AbstractTestNode right) { + public AddTestNode(AbstractTestNode left, AbstractTestNode right, boolean cfgAnchorBeforeReturn) { this.left = left; this.right = right; + this.cfgAnchorBeforeReturn = cfgAnchorBeforeReturn; + } + + public AddTestNode(AbstractTestNode left, AbstractTestNode right) { + this(left, right, false); } @Override public int execute(VirtualFrame frame) { - return left.execute(frame) + right.execute(frame); + int res = left.execute(frame) + right.execute(frame); + if (cfgAnchorBeforeReturn) { + GraalDirectives.controlFlowAnchor(); + } + return res; } } diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/nodes/RootTestNode.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/nodes/RootTestNode.java index 52832610d95e..a3ab16d791db 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/nodes/RootTestNode.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/nodes/RootTestNode.java @@ -24,6 +24,8 @@ */ package org.graalvm.compiler.truffle.test.nodes; +import org.graalvm.compiler.api.directives.GraalDirectives; + import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.NodeInfo; @@ -35,6 +37,7 @@ public class RootTestNode extends RootNode { private final String name; private final boolean internal; private final boolean captureFramesForTrace; + private final boolean cfgAnchorBeforeReturn; @Child private AbstractTestNode node; @@ -46,17 +49,30 @@ public RootTestNode(FrameDescriptor descriptor, String name, AbstractTestNode no this(descriptor, name, node, false, false); } + public RootTestNode(FrameDescriptor descriptor, String name, AbstractTestNode node, boolean cfgAnchorBeforeReturn) { + this(descriptor, name, node, false, false, cfgAnchorBeforeReturn); + } + public RootTestNode(FrameDescriptor descriptor, String name, AbstractTestNode node, boolean internal, boolean captureFramesForTrace) { + this(descriptor, name, node, captureFramesForTrace, internal, false); + } + + public RootTestNode(FrameDescriptor descriptor, String name, AbstractTestNode node, boolean internal, boolean captureFramesForTrace, boolean cfgAnchorBeforeReturn) { super(null, descriptor); this.name = name; this.node = node; this.internal = internal; this.captureFramesForTrace = captureFramesForTrace; + this.cfgAnchorBeforeReturn = cfgAnchorBeforeReturn; } @Override public Object execute(VirtualFrame frame) { - return node.execute(frame); + Object o = node.execute(frame); + if (cfgAnchorBeforeReturn) { + GraalDirectives.controlFlowAnchor(); + } + return o; } @Override diff --git a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/nodes/explosion/UnrollingTestNode.java b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/nodes/explosion/UnrollingTestNode.java index efa16263af76..180aa75cf7e5 100644 --- a/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/nodes/explosion/UnrollingTestNode.java +++ b/compiler/src/org.graalvm.compiler.truffle.test/src/org/graalvm/compiler/truffle/test/nodes/explosion/UnrollingTestNode.java @@ -361,6 +361,7 @@ public int execute(VirtualFrame frame) { GraalDirectives.blackhole(OUTSIDE_LOOP_MARKER); GraalDirectives.blackhole(i); CompilerAsserts.partialEvaluationConstant(i); + GraalDirectives.controlFlowAnchor(); } outer: for (int i = 0; i < count; i++) { GraalDirectives.blackhole(OUTER_LOOP_INSIDE_LOOP_MARKER); @@ -376,6 +377,7 @@ public int execute(VirtualFrame frame) { SideEffect1 = x; continue outer; } + GraalDirectives.controlFlowAnchor(); if (j == SideEffect2) { GraalDirectives.blackhole(CONTINUE_LOOP_MARKER); CompilerAsserts.partialEvaluationConstant(j); @@ -385,6 +387,7 @@ public int execute(VirtualFrame frame) { SideEffect1 = x; break; } + GraalDirectives.controlFlowAnchor(); if (j == SideEffect1) { GraalDirectives.blackhole(CONTINUE_LOOP_MARKER); CompilerAsserts.partialEvaluationConstant(j); @@ -394,6 +397,7 @@ public int execute(VirtualFrame frame) { SideEffect1 = x; continue outer; } + GraalDirectives.controlFlowAnchor(); } } GraalDirectives.blackhole(AFTER_LOOP_MARKER); @@ -614,6 +618,7 @@ public int execute(VirtualFrame frame) { // LEX 1 -> constant number of loop iterations break; } + GraalDirectives.controlFlowAnchor(); GraalDirectives.blackhole(INSIDE_LOOP_MARKER); SideEffect = i; if (i == SideEffect2) { @@ -626,6 +631,7 @@ public int execute(VirtualFrame frame) { CompilerAsserts.partialEvaluationConstant(i); return i; } + GraalDirectives.controlFlowAnchor(); if (i == SideEffect3) { // LEN 1 -> continue at header // that is the difference of unroll vs explode:unrolling will merge the ends, @@ -633,13 +639,16 @@ public int execute(VirtualFrame frame) { i++; continue; } + GraalDirectives.controlFlowAnchor(); if (i == SideEffect1) { // LEX 3 (2) -> continue at AFTER_LOOP_MARKER break; } + GraalDirectives.controlFlowAnchor(); i++; // LEN 2 -> continue at header } + GraalDirectives.controlFlowAnchor(); GraalDirectives.blackhole(AFTER_LOOP_MARKER); return count; } diff --git a/compiler/src/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java b/compiler/src/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java index 66f4511bb201..e0f37ee06461 100644 --- a/compiler/src/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java +++ b/compiler/src/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java @@ -95,7 +95,7 @@ public boolean runAnalysis(StructuredGraph graph, CoreProvidersT context) { schedule = null; cfg = ControlFlowGraph.compute(graph, true, true, false, false); } else { - new SchedulePhase(strategy).apply(graph, false); + new SchedulePhase(strategy).apply(graph, context, false); schedule = graph.getLastSchedule(); cfg = schedule.getCFG(); } diff --git a/compiler/src/org.graalvm.libgraal.jni/src/org/graalvm/libgraal/jni/LibGraalJNIMethodScope.java b/compiler/src/org.graalvm.libgraal.jni/src/org/graalvm/libgraal/jni/LibGraalJNIMethodScope.java new file mode 100644 index 000000000000..803e5d876b84 --- /dev/null +++ b/compiler/src/org.graalvm.libgraal.jni/src/org/graalvm/libgraal/jni/LibGraalJNIMethodScope.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.libgraal.jni; + +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; +import org.graalvm.nativebridge.jni.JNI.JNIEnv; +import org.graalvm.nativebridge.jni.JNIMethodScope; +import org.graalvm.nativeimage.c.type.CLongPointer; +import org.graalvm.word.PointerBase; +import org.graalvm.word.WordFactory; + +import static org.graalvm.nativebridge.jni.JNIUtil.PopLocalFrame; +import static org.graalvm.nativebridge.jni.JNIUtil.PushLocalFrame; + +/** + * A {@link JNIMethodScope} subclass which pushes a JNI locals frame when there is no Java frame + * anchor on the stack. A Java frame anchor means there is an active Java-to-native stub (see + * {@code SharedRuntime::generate_native_wrapper}) that will clear all JNI references in the current + * JNI locals frame after the native call returns. A call directly into libgraal from the VM does + * not use such a stub so without explicitly allocating a new JNI locals frame, the JNI references + * created by libgraal will never be freed (i.e., a memory leak). + */ +final class LibGraalJNIMethodScope extends JNIMethodScope { + + private static volatile int lastJavaPCOffset = -1; + + private LibGraalJNIMethodScope(String scopeName, JNIEnv env) { + super(scopeName, env); + PushLocalFrame(env, 64); + } + + @Override + public void close() { + setObjectResult(PopLocalFrame(getEnv(), getObjectResult())); + super.close(); + } + + /** + * Creates a new {@link JNIMethodScope} and pushes a JNI locals frame when the scope is a top + * level scope and there is no Java frame anchor on the stack. + * + * @see LibGraalJNIMethodScope + */ + static JNIMethodScope open(String scopeName, JNIEnv env) { + return scopeOrNull() == null && getJavaFrameAnchor().isNull() ? new LibGraalJNIMethodScope(scopeName, env) : new JNIMethodScope(scopeName, env); + } + + private static PointerBase getJavaFrameAnchor() { + CLongPointer currentThreadLastJavaPCOffset = (CLongPointer) WordFactory.unsigned(HotSpotJVMCIRuntime.runtime().getCurrentJavaThread()).add(getLastJavaPCOffset()); + return WordFactory.pointer(currentThreadLastJavaPCOffset.read()); + } + + private static int getLastJavaPCOffset() { + int res = lastJavaPCOffset; + if (res == -1) { + HotSpotVMConfigAccess configAccess = new HotSpotVMConfigAccess(HotSpotJVMCIRuntime.runtime().getConfigStore()); + int anchor = configAccess.getFieldOffset("JavaThread::_anchor", Integer.class, "JavaFrameAnchor"); + int lastJavaPc = configAccess.getFieldOffset("JavaFrameAnchor::_last_Java_pc", Integer.class, "address"); + res = anchor + lastJavaPc; + lastJavaPCOffset = res; + } + return res; + } +} diff --git a/compiler/src/org.graalvm.libgraal.jni/src/org/graalvm/libgraal/jni/LibGraalUtil.java b/compiler/src/org.graalvm.libgraal.jni/src/org/graalvm/libgraal/jni/LibGraalUtil.java index a3315aa54a86..21897b4a9aa7 100644 --- a/compiler/src/org.graalvm.libgraal.jni/src/org/graalvm/libgraal/jni/LibGraalUtil.java +++ b/compiler/src/org.graalvm.libgraal.jni/src/org/graalvm/libgraal/jni/LibGraalUtil.java @@ -46,7 +46,11 @@ private LibGraalUtil() { public static JNIMethodScope openScope(Class entryPointClass, Enum id, JNIEnv env) { Objects.requireNonNull(id, "Id must be non null."); - return new JNIMethodScope(entryPointClass.getSimpleName() + "::" + id, env); + return LibGraalJNIMethodScope.open(entryPointClass.getSimpleName() + "::" + id, env); + } + + public static JNIMethodScope openScope(String scopeName, JNIEnv env) { + return LibGraalJNIMethodScope.open(scopeName, env); } /*----------------- CHECKING ------------------*/ diff --git a/compiler/src/org.graalvm.libgraal/src/org/graalvm/libgraal/LibGraalScope.java b/compiler/src/org.graalvm.libgraal/src/org/graalvm/libgraal/LibGraalScope.java index 017136977664..11472e02566b 100644 --- a/compiler/src/org.graalvm.libgraal/src/org/graalvm/libgraal/LibGraalScope.java +++ b/compiler/src/org.graalvm.libgraal/src/org/graalvm/libgraal/LibGraalScope.java @@ -26,6 +26,7 @@ import java.lang.reflect.Method; import java.util.Arrays; +import java.util.concurrent.atomic.AtomicInteger; /** * Scope for calling CEntryPoints in libgraal. {@linkplain #LibGraalScope() Opening} a scope ensures @@ -42,18 +43,39 @@ public final class LibGraalScope implements AutoCloseable { static class Shared { final DetachAction detachAction; final LibGraalIsolate isolate; - final long isolateThread; + private long isolateThread; Shared(DetachAction detachAction, LibGraalIsolate isolate, long isolateThread) { this.detachAction = detachAction; this.isolate = isolate; this.isolateThread = isolateThread; } + + public long getIsolateThread() { + if (isolateThread == 0L) { + throw new IllegalStateException(Thread.currentThread() + " is no longer attached to " + isolate); + } + return isolateThread; + } + + public long detach() { + long res = getIsolateThread(); + isolateThread = 0L; + return res; + } + + @Override + public String toString() { + return String.format("isolate=%s, isolateThread=0x%x, detachAction=%s", isolate, isolateThread, detachAction); + } } private final LibGraalScope parent; private final Shared shared; + private static final AtomicInteger nextId = new AtomicInteger(1); + private final int id; + /** * Gets the current scope. * @@ -78,7 +100,7 @@ public static LibGraalScope current() { * @throws IllegalStateException if the current thread is not attached to libgraal */ public static long getIsolateThread() { - return current().shared.isolateThread; + return current().shared.getIsolateThread(); } /** @@ -128,6 +150,7 @@ public LibGraalScope(DetachAction detachAction) { if (LibGraal.inLibGraal() || !LibGraal.isAvailable()) { throw new IllegalStateException(); } + id = nextId.getAndIncrement(); parent = currentScope.get(); if (parent == null) { long[] isolateBox = {0}; @@ -143,6 +166,11 @@ public LibGraalScope(DetachAction detachAction) { currentScope.set(this); } + @Override + public String toString() { + return String.format("LibGraalScope@%d[%s, parent=%s]", id, shared, parent); + } + /** * Enters a scope for making calls into an existing libgraal isolate. If there is no existing * libgraal scope for the current thread, the current thread is attached to libgraal. When the @@ -159,6 +187,7 @@ public LibGraalScope(long isolateAddress) { if (LibGraal.inLibGraal() || !LibGraal.isAvailable()) { throw new IllegalStateException(); } + id = nextId.getAndIncrement(); parent = currentScope.get(); if (parent == null) { long isolateThread = getIsolateThreadIn(isolateAddress); @@ -223,19 +252,26 @@ public LibGraalIsolate getIsolate() { * Gets the address of the isolate thread associated with this scope. */ public long getIsolateThreadAddress() { - return shared.isolateThread; + return shared.getIsolateThread(); } @Override public void close() { + // Reset the currentScope thread local before detaching. Detaching may trigger HotSpot to + // shutdown the libgraal isolate. That involves re-attaching the current thread to the + // libgraal isolate with a *new* isolate thread for calling + // HotSpotJVMCIRuntime.shutdown(). In the scope of the latter call, if a new LibGraalScope + // is opened, it must not see this LibGraalScope as its parent otherwise it will use the + // closed and discarded isolate thread (i.e. this.shared.isolateThread). + currentScope.set(parent); if (parent == null && shared.detachAction != null) { + long isolateThread = shared.detach(); if (shared.detachAction == DetachAction.DETACH) { - detachThreadFrom(shared.isolateThread); + detachThreadFrom(isolateThread); } else { LibGraal.detachCurrentThread(shared.detachAction == DetachAction.DETACH_RUNTIME_AND_RELEASE); } } - currentScope.set(parent); } // Shared support for the LibGraal overlays diff --git a/compiler/src/org.graalvm.micro.benchmarks/src/micro/benchmarks/TypecheckBenchmark.java b/compiler/src/org.graalvm.micro.benchmarks/src/micro/benchmarks/TypecheckBenchmark.java new file mode 100644 index 000000000000..ad0bb7f25eea --- /dev/null +++ b/compiler/src/org.graalvm.micro.benchmarks/src/micro/benchmarks/TypecheckBenchmark.java @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package micro.benchmarks; + +import java.lang.reflect.Array; +import java.util.Random; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; + +public class TypecheckBenchmark extends BenchmarkBase { + + static class A { + + } + + static class B { + + } + + static class C { + + } + + static class AA { + + } + + static class AA1 extends AA { + + } + + static class AA2 extends AA1 { + + } + + static class BB { + + } + + static class BB1 extends BB { + + } + + static class BB2 extends BB1 { + + } + + static class CC { + + } + + static class CC1 extends CC { + + } + + static class CC2 extends CC1 { + + } + + @State(Scope.Benchmark) + public static class ThreadState { + + private static final int N = 100000; + + final Random r = new Random(17); + + final C c = new C(); + final B b = new B(); + final A a = new A(); + final CC2 cc2 = new CC2(); + final CC1 cc1 = new CC1(); + final CC cc = new CC(); + final BB2 bb2 = new BB2(); + final BB1 bb1 = new BB1(); + final BB bb = new BB(); + final AA2 aa2 = new AA2(); + final AA1 aa1 = new AA1(); + final AA aa = new AA(); + Random r1 = new Random(31); + + int magic = 14; + + Object[] aas = createAAs(); + Class[] classes = createClasses(N); + Object[] object = createObjects(N); + + private Object[] createAAs() { + Object[] source = new Object[N]; + for (int i = 0; i < N; i++) { + if (i == magic) { + source[i] = new CC(); + } + int rand = r.nextInt(3); + if (rand <= 1) { + source[i] = new AA2(); + } else { + source[i] = new AA1(); + } + } + return source; + } + + private Class[] createClasses(int n2) { + Class[] ccs = new Class[n2]; + for (int i = 0; i < N; i++) { + ccs[i] = nextClass(); + } + return ccs; + } + + private Object[] createObjects(int n2) { + Object[] o = new Object[n2]; + for (int i = 0; i < N; i++) { + o[i] = nextElement(); + } + return o; + } + + private Object nextElement() { + int rand = r.nextInt(12); + + if (rand == 10) { + return aa2; + } else if (rand == 11) { + return bb2; + } else if (rand == 12) { + return cc2; + } else if (rand == 9) { + return c; + } else if (rand == 8) { + return b; + } else if (rand == 7) { + return a; + } else if (rand == 6) { + return cc1; + } else if (rand == 5) { + return cc; + } else if (rand == 4) { + return bb1; + } else if (rand == 3) { + return bb; + } else if (rand == 2) { + return aa1; + } + return aa; + } + + private Class nextClass() { + int rand = r1.nextInt(10); + + if (rand == 9) { + return C.class; + } else if (rand == 8) { + return B.class; + } else if (rand == 7) { + return A.class; + } else if (rand == 6) { + return CC1.class; + } else if (rand == 5) { + return CC.class; + } else if (rand == 4) { + return BB1.class; + } else if (rand == 3) { + return BB.class; + } else if (rand == 2) { + return AA1.class; + } + return AA.class; + } + } + + @Benchmark + public void benchArrayStore(ThreadState state) { + Object[] target = (Object[]) Array.newInstance(state.aas[0].getClass().getSuperclass(), state.aas.length); + for (int i = 0; i < state.aas.length; i++) { + if (i == state.magic) { + continue; + } + target[i] = state.aas[i]; + } + } + + @Benchmark + public int repetitiveTypeCheckExact(ThreadState state) { + int res = 0; + for (int i = 0; i < state.object.length; i++) { + Object o = state.object[i]; + if (o instanceof A) { + res++; + } else if (o instanceof B) { + res += 2; + } else if (o instanceof C) { + res += 4; + } + } + return res; + } + + @Benchmark + public int repetitiveTypeCheckSubclasses(ThreadState state) { + int res = 0; + for (int i = 0; i < state.object.length; i++) { + Object o = state.object[i]; + if (o == null) { + return 0; + } + if (o instanceof AA1) { + res += 7; + } else if (o instanceof BB1) { + res += 5; + } else if (o instanceof CC1) { + res += 3; + } else if (o instanceof AA) { + res++; + } else if (o instanceof BB) { + res += 2; + } else if (o instanceof CC) { + res += 4; + } + } + return res; + } + + @Benchmark + public int repetitiveClassIsAssignable(ThreadState state) { + int res = 0; + for (int i = 0; i < state.object.length; i++) { + Object o = state.object[i]; + if (o == null) { + return 0; + } + if (AA1.class.isAssignableFrom(o.getClass())) { + res += 7; + } else if (BB1.class.isAssignableFrom(o.getClass())) { + res += 3; + } else if (CC1.class.isAssignableFrom(o.getClass())) { + res += 5; + } else if (AA.class.isAssignableFrom(o.getClass())) { + res++; + } else if (BB.class.isAssignableFrom(o.getClass())) { + res += 2; + } else if (CC.class.isAssignableFrom(o.getClass())) { + res += 4; + } + } + return res; + } + + @Benchmark + public int repetitiveInstanceOfDynamic(ThreadState state) { + int res = 0; + for (int i = 0; i < state.object.length / 8; i += 8) { + Object o1 = state.object[i]; + Object o2 = state.object[i + 1]; + Object o3 = state.object[i + 2]; + Object o4 = state.object[i + 3]; + Object o5 = state.object[i + 4]; + Object o6 = state.object[i + 5]; + Object o7 = state.object[i + 6]; + Object o8 = state.object[i + 7]; + Class c = state.classes[i]; + + if (c.isInstance(o1)) { + res++; + } else if (c.isInstance(o2)) { + res++; + } else if (c.isInstance(o3)) { + res++; + } else if (c.isInstance(o4)) { + res++; + } else if (c.isInstance(o5)) { + res++; + } else if (c.isInstance(o6)) { + res++; + } else if (c.isInstance(o7)) { + res++; + } else if (c.isInstance(o8)) { + res++; + } + } + + return res; + } + + @Benchmark + public boolean classIsAssignableFromShouldFold(ThreadState state) { + return AA.class.isAssignableFrom(state.aa1.getClass()); + } + + @Benchmark + public boolean classIsInstanceShouldFold(ThreadState state) { + return AA.class.isInstance(state.aa1); + } + + @Benchmark + public boolean instanceOfClassShouldFold(ThreadState state) { + return state.aa1 instanceof AA; + } + + @Benchmark + public int classIsAssignableFrom(ThreadState state) { + int res = 0; + Object[] objects = state.object; + for (int i = 0; i < objects.length; i++) { + if (classIsAssignableFrom(objects[i])) { + res++; + } + } + return res; + } + + boolean classIsAssignableFrom(Object obj) { + return AA1.class.isAssignableFrom(obj.getClass()); + } + + @Benchmark + public int classIsInstance(ThreadState state) { + int res = 0; + Object[] objects = state.object; + for (int i = 0; i < objects.length; i++) { + if (classIsInstance(objects[i])) { + res++; + } + } + return res; + } + + boolean classIsInstance(Object obj) { + return AA1.class.isInstance(obj); + } + + @Benchmark + public int instanceOfClass(ThreadState state) { + int res = 0; + Object[] objects = state.object; + for (int i = 0; i < objects.length; i++) { + if (instanceOfClass(objects[i])) { + res++; + } + } + return res; + } + + boolean instanceOfClass(Object obj) { + return obj instanceof AA1; + } +} diff --git a/compiler/src/org.graalvm.nativebridge.jni/src/org/graalvm/nativebridge/jni/JNIMethodScope.java b/compiler/src/org.graalvm.nativebridge.jni/src/org/graalvm/nativebridge/jni/JNIMethodScope.java index 2ce314d41beb..26f9d0c81171 100644 --- a/compiler/src/org.graalvm.nativebridge.jni/src/org/graalvm/nativebridge/jni/JNIMethodScope.java +++ b/compiler/src/org.graalvm.nativebridge.jni/src/org/graalvm/nativebridge/jni/JNIMethodScope.java @@ -24,8 +24,6 @@ */ package org.graalvm.nativebridge.jni; -import static org.graalvm.nativebridge.jni.JNIUtil.PopLocalFrame; -import static org.graalvm.nativebridge.jni.JNIUtil.PushLocalFrame; import static org.graalvm.nativebridge.jni.JNIUtil.getFeatureName; import org.graalvm.nativebridge.jni.JNI.JNIEnv; @@ -42,7 +40,7 @@ * {@linkplain #getObjectResult() retrieved} and returned outside the try-with-resources statement. * This is necessary to support use of JNI local frames. */ -public final class JNIMethodScope implements AutoCloseable { +public class JNIMethodScope implements AutoCloseable { private static final ThreadLocal topScope = new ThreadLocal<>(); @@ -104,9 +102,6 @@ public JNIMethodScope(String scopeName, JNIEnv env) { JNIMethodScope top = topScope.get(); this.env = env; if (top == null) { - // Only push a JNI frame for the top level native method call. - // HotSpot's JNI implementation currently ignores the `capacity` argument - PushLocalFrame(env, 64); top = this; parent = null; topScope.set(this); @@ -143,7 +138,6 @@ public void close() { throw new IllegalStateException("Unexpected JNI scope: " + topScope.get()); } topScope.set(null); - objResult = PopLocalFrame(env, objResult); } else { JNIMethodScope top = parent; while (top.parent != null) { diff --git a/compiler/src/org.graalvm.nativebridge.jni/src/org/graalvm/nativebridge/jni/JNIUtil.java b/compiler/src/org.graalvm.nativebridge.jni/src/org/graalvm/nativebridge/jni/JNIUtil.java index 0bc1118c03d2..90806131490d 100644 --- a/compiler/src/org.graalvm.nativebridge.jni/src/org/graalvm/nativebridge/jni/JNIUtil.java +++ b/compiler/src/org.graalvm.nativebridge.jni/src/org/graalvm/nativebridge/jni/JNIUtil.java @@ -79,6 +79,10 @@ public final class JNIUtil { "getPlatformClassLoader", "()Ljava/lang/ClassLoader;" }; + private static final String[] METHOD_GET_SYSTEM_CLASS_LOADER = { + "getSystemClassLoader", + "()Ljava/lang/ClassLoader;" + }; private static final String[] METHOD_LOAD_CLASS = { "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;" @@ -513,6 +517,24 @@ public static JObject getJVMCIClassLoader(JNIEnv env) { } } + /** + * Returns the {@link ClassLoader#getSystemClassLoader()}. + */ + public static JObject getSystemClassLoader(JNIEnv env) { + JClass clazz; + try (CCharPointerHolder className = CTypeConversion.toCString(JNIUtil.getBinaryName(ClassLoader.class.getName()))) { + clazz = JNIUtil.FindClass(env, className.get()); + } + if (clazz.isNull()) { + throw new InternalError("No such class " + ClassLoader.class.getName()); + } + JMethodID getClassLoaderId = findMethod(env, clazz, true, true, METHOD_GET_SYSTEM_CLASS_LOADER[0], METHOD_GET_SYSTEM_CLASS_LOADER[1]); + if (getClassLoaderId.isNull()) { + throw new InternalError(String.format("Cannot find method %s in class %s.", METHOD_GET_SYSTEM_CLASS_LOADER[0], ClassLoader.class.getName())); + } + return env.getFunctions().getCallStaticObjectMethodA().call(env, clazz, getClassLoaderId, nullPointer()); + } + public static JMethodID findMethod(JNIEnv env, JClass clazz, boolean staticMethod, String methodName, String methodSignature) { return findMethod(env, clazz, staticMethod, false, methodName, methodSignature); } diff --git a/docs/enterprise-overview/architecture-overview.md b/docs/enterprise-overview/architecture-overview.md index 512e250d54ff..86be95af91ad 100644 --- a/docs/enterprise-overview/architecture-overview.md +++ b/docs/enterprise-overview/architecture-overview.md @@ -10,12 +10,12 @@ It is designed to accelerate the execution of applications written in Java and o GraalVM Enterprise's polyglot capabilities make it possible to mix multiple programming languages in a single application while eliminating any foreign language call costs. This page provides developers, solution architects, and infrastructure architects with an architectural overview of GraalVM Enterprise, as well as information about runtime modes, supported platforms, available distributions, core and additional functionalities, and support levels for various features. -The conceptual overview and advantages of GraalVM Enterprise are described on the [Solutions Overview](https://docs.oracle.com/en/graalvm/enterprise/21/docs/overview/) page. +The conceptual overview and advantages of GraalVM Enterprise are described on the [Solutions Overview](solutions-overview.md) page. * [GraalVM Enterprise Architecture](#graalvm-enterprise-architecture) * [Runtime Modes](#runtime-modes) * [Available Distributions](#available-distributions) -* [Supported Platforms](#supported-platforms) +* [Certified Platforms](#certified-platforms) * [Distribution Components List](#distribution-components-list) * [Licensing and Support](#licensing-and-support) * [Experimental and Early Adopter Features](#experimental-and-early-adopter-features) @@ -29,38 +29,37 @@ The conceptual overview and advantages of GraalVM Enterprise are described on th The preceding diagram illustrates a complete high-level architecture of GraalVM Enterprise. -GraalVM adds an [advanced just-in-time (JIT) optimizing compiler](/reference-manual/compiler/), which is written in Java, to the HotSpot Java Virtual Machine. +GraalVM adds an [advanced just-in-time (JIT) optimizing compiler](../reference-manual/compiler.md), which is written in Java, to the HotSpot Java Virtual Machine. -In addition to running Java and JVM-based languages, GraalVM's [Truffle language implementation framework](/graalvm-as-a-platform/language-implementation-framework/) makes it possible to run JavaScript, Ruby, Python, and a number of other popular languages on the JVM. -With GraalVM Truffle, Java and other supported languages can directly interoperate with each other and pass data back and forth in the same memory space. +In addition to running Java and JVM-based languages, [GraalVM's language implementation framework (Truffle)](../../truffle/docs/README.md), makes it possible to run JavaScript, Ruby, Python, and a number of other popular languages on the JVM. +With Truffle, Java and other supported languages can directly interoperate with each other and pass data back and forth in the same memory space. ## Runtime Modes GraalVM Enterprise is unique as a runtime environment offering several modes of operation: JVM runtime mode, Native Image, Java on Truffle (the same Java applications can be run on either). #### JVM Runtime Mode -When running programs on the HotSpot JVM, GraalVM defaults to the [GraalVM compiler](/reference-manual/compiler/) as the top-tier JIT compiler. +When running programs on the HotSpot JVM, GraalVM defaults to the [GraalVM compiler](../reference-manual/compiler.md) as the top-tier JIT compiler. At runtime, an application is loaded and executed normally on the JVM. The JVM passes bytecodes for Java or any other JVM-native language to the compiler, which compiles that to the machine code and returns it to the JVM. -Interpreters for supported languages, written on top of the [Truffle framework](/graalvm-as-a-platform/language-implementation-framework/), are themselves Java programs that run on the JVM. +Interpreters for supported languages, written on top of the [Truffle framework](../../truffle/docs/README.md), are themselves Java programs that run on the JVM. #### Native Image -[Native Image](/reference-manual/native-image/) is an innovative technology that compiles Java code into a standalone binary executable or a native shared library. +[Native Image](../reference-manual/native-image/README.md) is an innovative technology that compiles Java code into a standalone binary executable or a native shared library. The Java bytecode that is processed during the native image build includes all application classes, dependencies, third party dependent libraries, and any JDK classes that are required. A generated self-contained native executable is specific to each individual operating systems and machine architecture that does not require a JVM. #### Java on Truffle -[Java on Truffle](/reference-manual/java-on-truffle/) is an implementation of the Java Virtual Machine Specification, built with the [Truffle language implementation framework](/graalvm-as-a-platform/language-implementation-framework/). +[Java on Truffle](../reference-manual/java-on-truffle/README.md) is an implementation of the Java Virtual Machine Specification, built with the [Truffle framework](../../truffle/docs/README.md). It is a complete Java VM that includes all core components, implements the same API as the Java Runtime Environment library, and reuses all JARs and native libraries from GraalVM. Java on Trufle is an experimental technology in GraalVM, available as of version 21.0.0. ## Available Distributions -GraalVM Enterprise distributions are based on Oracle JDK 8, 11, and 16. +GraalVM Enterprise distributions are based on Oracle JDK 8, 11, and 17. GraalVM Enterprise releases include all Oracle Java critical patch updates (CPUs), which are released on a regular schedule to remedy defects and known vulnerabilities. GraalVM Enterprise is available for Linux, macOS, and Windows platforms on x86 64-bit systems, and for Linux on ARM 64-bit system. -The GraalVM Enterprise distribution based on Oracle JDK 16 is experimental with [several known limitations](https://docs.oracle.com/en/graalvm/enterprise/21/docs/overview/known-issues/). Depending on the platform, the distributions are shipped as *.tar.gz* or *.zip* archives. ## Certified Platforms @@ -69,10 +68,10 @@ The following are the certified platforms for GraalVM Enterprise 21: | Operating System | Version | Architecture | Installation Guide | |------------------------------------ |-------------- |-------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Oracle Linux | 7, 8 | x86 64-bit, ARM 64-bit | [Installation Guide for Linux](/getting-started/installation-linux/) | -| Red Hat Enterprise Linux(RHEL) | 7, 8 | x86 64-bit | [Installation Guide for Linux](/getting-started/installation-linux/) | -| macOS | 10.14 (Mojave), 10.15 (Catalina) | x86 64-bit | [Installation Guide for macOS](/getting-started/installation-macos/) | -| Microsoft Windows | Server 2016, 2019 | x86 64-bit | [Installation Guide for Windows](/getting-started/installation-windows/) | +| Oracle Linux | 7, 8 | x86 64-bit, ARM 64-bit | [Installation Guide for Linux](../getting-started/graalvm-enterprise/oci/compute-instances.md) | +| Red Hat Enterprise Linux(RHEL) | 7, 8 | x86 64-bit | [Installation Guide for Linux](../getting-started/graalvm-enterprise/installation-linux.md) | +| macOS | 10.14 (Mojave), 10.15 (Catalina) | x86 64-bit | [Installation Guide for macOS](../getting-started/graalvm-enterprise/installation-macos.md) | +| Microsoft Windows | Server 2016, 2019 | x86 64-bit | [Installation Guide for Windows](../getting-started/graalvm-enterprise/installation-windows.md) | ## Distribution Components List @@ -91,24 +90,24 @@ GraalVM Enterprise consists of core and additional functionalities. **Utilities** * JavaScript REPL with the JavaScript interpreter * `lli` tool to directly execute programs from LLVM bitcode -* [GraalVM Updater](/reference-manual/graalvm-updater/) to install additional functionalities +* [GraalVM Updater](../reference-manual/graalvm-updater.md) to install additional functionalities ### Additional Functionalities GraalVM Enterprise core installation can be extended with more languages runtimes and utilities. Tools/Utilities: -* [Native Image](/reference-manual/native-image/) -- a technology to compile an application ahead-of-time into a native platform executable. -* [LLVM toolchain](/reference-manual/llvm/) -- a set of tools and APIs for compiling native programs to bitcode that can be executed on GraalVM. -* [Java on Truffle](/reference-manual/java-on-truffle/) -- a JVM implementation built upon the [Truffle framework](/graalvm-as-a-platform/language-implementation-framework/) to run Java via a Java bytecode interpreter. +* [Native Image](../reference-manual/native-image/README.md) -- a technology to compile an application ahead-of-time into a native platform executable. +* [LLVM toolchain](../reference-manual/llvm/README.md) -- a set of tools and APIs for compiling native programs to bitcode that can be executed on GraalVM. Runtimes: -* [Node.js](/reference-manual/js/) -- the Node.js 14.16.1 runtime for JavaScript -* [Python](/reference-manual/python/) -- Python 3.8.5 compatible -* [Ruby](/reference-manual/ruby/) -- Ruby 2.7.3 compatible -* [R](/reference-manual/r/) -- GNU R 4.0.3 compatible -* [GraalWasm](/reference-manual/wasm/) -- WebAssembly (Wasm) +* [Java on Truffle](../reference-manual/java-on-truffle/README.md) -- a JVM implementation built upon the [Truffle framework](../../truffle/docs/README.md) to run Java via a Java bytecode interpreter. +* [Node.js](../reference-manual/js/README.md) -- the Node.js 14.17.6 runtime for JavaScript +* [Python](../reference-manual/python/README.md) -- Python 3.8.5 compatible +* [Ruby](../reference-manual/ruby/README.md) -- Ruby 2.7.3 compatible +* [R](../reference-manual/r/README.md) -- GNU R 4.0.3 compatible +* [GraalWasm](../reference-manual/wasm/README.md) -- WebAssembly (Wasm) ## Licensing and Support @@ -143,9 +142,9 @@ The following table lists supported and experimental features in GraalVM Enterpr ## What to Read Next -Users who are new to GraalVM Enterprise or have little experience using it, continue to [Getting Started with GraalVM Enterprise](/getting-started//#install-graalvm-enterprise). +Users who are new to GraalVM Enterprise or have little experience using it, continue to [Getting Started with GraalVM Enterprise](../getting-started/graalvm-enterprise/get-started-graalvm-enterprise.md). Download and install GraalVM Enterprise on your local machine, try running the examples provided in the guide, or test GraalVM Enterprise with your workload. -We suggest you then look at more complex [Examples Applications](/docs/examples/). +We suggest you then look at more complex [Examples Applications](../examples/examples.md). -Developers, who have GraalVM Enterprise already installed or have experience using it in the past, can skip the getting started guide and proceed to the [Reference Manuals](/reference-manual/) for +Developers, who have GraalVM Enterprise already installed or have experience using it in the past, can skip the getting started guide and proceed to the [Reference Manuals](../reference-manual/reference-manuals.md) for in-depth coverage of GraalVM Enterprise technologies. diff --git a/docs/enterprise-overview/solutions-overview.md b/docs/enterprise-overview/solutions-overview.md index 1f7a5dc3b625..25bcd89418b9 100644 --- a/docs/enterprise-overview/solutions-overview.md +++ b/docs/enterprise-overview/solutions-overview.md @@ -96,7 +96,7 @@ vulnerabilities. ## Get Started with GraalVM Enterprise -[Get started with GraalVM Enterprise](/getting-started/) and: +[Get started with GraalVM Enterprise](../getting-started/graalvm-enterprise/get-started-graalvm-enterprise.md) and: * reduce IT and storage costs * provide customers with quicker response time * employ fewer resources, freeing up CPU diff --git a/docs/examples/examples.md b/docs/examples/examples.md index 56add0222ed7..dc996a9ca382 100644 --- a/docs/examples/examples.md +++ b/docs/examples/examples.md @@ -20,5 +20,5 @@ Here you can also find an even more sophisticated example of polyglot native exe The [Java/Kotlin Native Image Example](java-kotlin-aot.md) demonstrates how to compile a Java and Kotlin application ahead-of-time, and illustrates the performance gain. -The [Oracle Database Example](examples/mle-oracle.md) contains instructions on how to run the Oracle Database Multilingual Engine (MLE) which is the integration of GraalVM in the Oracle +The [Oracle Database Example](mle-oracle.md) contains instructions on how to run the Oracle Database Multilingual Engine (MLE) which is the integration of GraalVM in the Oracle Database 21c. diff --git a/docs/examples/java-kotlin-aot.md b/docs/examples/java-kotlin-aot.md index 725c4b71cf6f..547f3815dabd 100644 --- a/docs/examples/java-kotlin-aot.md +++ b/docs/examples/java-kotlin-aot.md @@ -7,59 +7,56 @@ permalink: /examples/java-kotlin-aot/ # Build a Native Image of a Java and Kotlin Application -This example demonstrates how to compile a Java and Kotlin application -ahead-of-time into a native executable, and illustrates the advantages. +This example demonstrates how to compile a Java and Kotlin application ahead-of-time into a native executable, and illustrates the advantages. -### Preparation - -This example requires the [Maven](https://maven.apache.org/) build tool. +## Preparation 1. Download or clone the repository and navigate into the `java-kotlin-aot` directory: -```shell -git clone https://github.com/graalvm/graalvm-demos -cd graalvm-demos/java-kotlin-aot -``` -This is a simple Java and Kotlin application showing how easy it is to -interoperate between JVM-based languages. A Java method accesses a String from -Kotlin and calls a Kotlin function, which later accesses a String from a Java -class. Before running this example, you need to build the application. -Note: You can use any JDK for building the application. However, `javac` from GraalVM -in the build script is used to simplify the prerequisites so another JDK does not need to be installed. - -2. Having installed GraalVM, export the home directory as `$GRAALVM_HOME` and add `$GRAALVM_HOME/bin` -to the path, using a command-line shell for Linux: -```shell -export GRAALVM_HOME=/home/${current_user}/path/to/graalvm -``` -For macOS, use: -```shell -export GRAALVM_HOME=/Users/${current_user}/path/to/graalvm/Contents/Home -``` -Note that your paths are likely to be different depending on the download location. - -3. [Install Native Image](../reference-manual/native-image/README.md/#install-native-image) to make use of the `native-image` utility. + Note: You can use any JDK for building the application. However, `javac` from GraalVM in the build script is used to simplify the prerequisites so another JDK does not need to be installed. + +2. [Download GraalVM](https://www.graalvm.org/downloads/), unzip the archive, export the GraalVM home directory as the `$JAVA_HOME` and add `$JAVA_HOME/bin` to the `PATH` environment variable: + On Linux: + ```bash + export JAVA_HOME=/home/${current_user}/path/to/graalvm + export PATH=$JAVA_HOME/bin:$PATH + ``` + On macOS: + ```bash + export JAVA_HOME=/Users/${current_user}/path/to/graalvm/Contents/Home + export PATH=$JAVA_HOME/bin:$PATH + ``` + On Windows: + ```bash + setx /M JAVA_HOME "C:\Progra~1\Java\" + setx /M PATH "C:\Progra~1\Java\\bin;%PATH%" + ``` + Note that your paths are likely to be different depending on the download location. + +3. [Install Native Image](../reference-manual/native-image/README.md/#install-native-image) by running. + ```bash + gu install native-image + ``` 4. Then execute: -```shell -./build.sh -``` + ```shell + ./build.sh + ``` Have a look at the `build.sh` script which creates a native executable from a Java class. The `native-image` utility compiles the application ahead-of-time for faster startup and lower general overhead at runtime. ```shell -$GRAALVM_HOME/bin/native-image -cp ./target/mixed-code-hello-world-1.0-SNAPSHOT.jar -H:Name=helloworld -H:Class=hello.JavaHello -H:+ReportUnsupportedElementsAtRuntime --allow-incomplete-classpath +$JAVA_HOME/bin/native-image --no-fallback -cp ./target/mixed-code-hello-world-1.0-SNAPSHOT-jar-with-dependencies.jar -H:Name=helloworld -H:Class=hello.JavaHello -H:+ReportUnsupportedElementsAtRuntime ``` -It takes a few parameters: the classpath, the main class of the application with -`-H:Class=...`, and the name of the resulting executable with `-H:Name=...`. +It takes a few parameters: the classpath, the main class of the application with `-H:Class=...`, and the name of the resulting executable with `-H:Name=...`. -After executing the `native-image` command, check the directory. It should have -produced the executable file, `helloworld`. +After executing the `native-image` command, check the directory. +It should have produced the executable file, `helloworld`. -### Running the Application +## Running the Application -To run the application, you need to execute the JAR file in the `target` dir. +To run the application, you need to execute the JAR file in the `target` directory. You can run it as a normal Java application using `java`. Or, since we have a native executable prepared, you can run that directly. The `run.sh` file executes both, and times them with the `time` utility: diff --git a/docs/examples/java-performance-examples.md b/docs/examples/java-performance-examples.md index b5bc2f71ddb0..fac22c279137 100644 --- a/docs/examples/java-performance-examples.md +++ b/docs/examples/java-performance-examples.md @@ -7,19 +7,17 @@ permalink: /examples/java-performance-examples/ # Java Performance Examples -The GraalVM compiler achieves excellent performance, especially for highly -abstracted programs, due to its versatile optimization techniques. Code using -more abstraction and modern Java features like Streams or Lambdas will see -greater speedups. The examples below demonstrate this. +The GraalVM compiler achieves excellent performance, especially for highly abstracted programs, due to its versatile optimization techniques. +Code using more abstraction and modern Java features like Streams or Lambdas will see greater speedups. +The examples below demonstrate this. -### Running Examples +## Running Examples -#### Streams API Example +### Streams API Example -A simple example based on the [Streams API](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html) -is used here to demonstrate performance gains when using the GraalVM compiler. -This example counts the number of uppercase characters in a body of text. To -simulate a large load, the same sentence is processed 10 million times: +A simple example based on the [Streams API](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html) is used here to demonstrate performance gains when using the GraalVM compiler. +This example counts the number of uppercase characters in a body of text. +To simulate a large load, the same sentence is processed 10 million times: 1. Save the following code snippet to a file named `CountUppercase.java`: @@ -49,62 +47,54 @@ public class CountUppercase { ```shell javac CountUppercase.java java CountUppercase In 2021 I would like to run ALL languages in one VM. -1 (297 ms) -2 (452 ms) -3 (136 ms) -4 (88 ms) -5 (107 ms) -6 (135 ms) -7 (88 ms) -8 (87 ms) -9 (78 ms) -total: 69999993 (1550 ms) +1 (319 ms) +2 (275 ms) +3 (164 ms) +4 (113 ms) +5 (100 ms) +6 (124 ms) +7 (86 ms) +8 (76 ms) +9 (77 ms) +total: 69999993 (1414 ms) ``` -The warmup time depends on numerous factors like the source code or how -many cores a machine has. If the performance profile of `CountUppercase` on your -machine does not match the above, run it for more iterations by adding -`-Diterations=N` just after `java` for some `N` greater than 1. +The warmup time depends on numerous factors like the source code or how many cores a machine has. +If the performance profile of `CountUppercase` on your machine does not match the above, run it for more iterations by adding `-Diterations=N` just after `java` for some `N` greater than 1. 3. Add the `-Dgraal.PrintCompilation=true` option to see statistics for the compilations: ```shell java -Dgraal.PrintCompilation=true CountUppercase In 2021 I would like to run ALL languages in one VM. ``` -This option prints a line after each compilation that shows the method -compiled, time taken, bytecodes processed (including inlined methods), size -of machine code produced, and amount of memory allocated during compilation. +This option prints a line after each compilation that shows the method compiled, time taken, bytecodes processed (including inlined methods), size of machine code produced, and amount of memory allocated during compilation. -4. Use the `-XX:-UseJVMCICompiler` option to disable the GraalVM compiler and -use the native top tier compiler in the VM to compare performance: +4. Use the `-XX:-UseJVMCICompiler` option to disable the GraalVM compiler and use the native top tier compiler in the VM to compare performance: ```shell java -XX:-UseJVMCICompiler CountUppercase In 2021 I would like to run ALL languages in one VM. -1 (747 ms) -2 (806 ms) -3 (640 ms) -4 (771 ms) -5 (606 ms) -6 (582 ms) -7 (623 ms) -8 (564 ms) -9 (682 ms) -total: 69999993 (6713 ms) +1 (492 ms) +2 (441 ms) +3 (443 ms) +4 (470 ms) +5 (422 ms) +6 (382 ms) +7 (407 ms) +8 (425 ms) +9 (343 ms) +total: 69999993 (4249 ms) ``` -The preceding example demonstrates the benefits of partial escape analysis (PEA) -and advanced inlining, which combine to significantly reduce heap allocation. +The preceding example demonstrates the benefits of partial escape analysis (PEA) and advanced inlining, which combine to significantly reduce heap allocation. The results were obtained using Oracle GraalVM Enterprise Edition. -The GraalVM Community Edition still has good performance compared to the native top-tier -compiler as shown below. You can simulate the Community Edition on the Enterprise Edition -by adding the option `-Dgraal.CompilerConfiguration=community`. +The GraalVM Community Edition still has good performance compared to the native top-tier compiler as shown below. +You can simulate the Community Edition on the Enterprise Edition by adding the option `-Dgraal.CompilerConfiguration=community`. -#### Sunflow Example +### Sunflow Example [Sunflow](http://sunflow.sourceforge.net) is an open source rendering engine. The following example is a simplified version of the Sunflow engine core code. -It performs calculations to blend various values for a point of light in a -rendered scene. +It performs calculations to blend various values for a point of light in a rendered scene. 1. Save the following code snippet to a file named `Blender.java`: ```java diff --git a/docs/examples/java-simple-stream-benchmark.md b/docs/examples/java-simple-stream-benchmark.md index c30306063bb3..67a0502e3318 100644 --- a/docs/examples/java-simple-stream-benchmark.md +++ b/docs/examples/java-simple-stream-benchmark.md @@ -7,49 +7,49 @@ permalink: /examples/java-simple-stream-benchmark/ # Simple Java Stream Benchmark -This application is a small benchmark of the Java Stream API. It demonstrates how -the GraalVM compiler can achieve better performance for highly -abstracted programs like those using Streams, Lambdas, or other Java features. - -### Preparation - -This example requires the [Maven](https://maven.apache.org/) build tool. - -1. Download or clone the repository and navigate into the `java-simple-stream-benchmark` directory: -```shell -git clone https://github.com/graalvm/graalvm-demos -cd graalvm-demos/java-simple-stream-benchmark -``` - -2. Build the benchmark. You can manually execute `mvn package`, but there is also -a `build.sh` script included for your convenience: -```shell -./build.sh -``` - -3. Export the GraalVM home directory as the `$GRAALVM_HOME` and add `$GRAALVM_HOME/bin` -to the path, using a command-line shell for Linux: -```shell -export GRAALVM_HOME=/path/to/graalvm -``` -For macOS: -```shell -export GRAALVM_HOME=/path/to/graalvm/Contents/Home -``` - +This application is a small benchmark of the Java Stream API. It demonstrates how the GraalVM compiler can achieve better performance for highly abstracted programs like those using Streams, Lambdas, or other Java features. + +## Preparation + +1. [Download GraalVM](https://www.graalvm.org/downloads/), unzip the archive, export the GraalVM home directory as the `$JAVA_HOME` and add `$JAVA_HOME/bin` to the `PATH` environment variable: + On Linux: + ```bash + export JAVA_HOME=/home/${current_user}/path/to/graalvm + export PATH=$JAVA_HOME/bin:$PATH + ``` + On macOS: + ```bash + export JAVA_HOME=/Users/${current_user}/path/to/graalvm/Contents/Home + export PATH=$JAVA_HOME/bin:$PATH + ``` + On Windows: + ```bash + setx /M JAVA_HOME "C:\Progra~1\Java\" + setx /M PATH "C:\Progra~1\Java\\bin;%PATH%" + ``` + Note that your paths are likely to be different depending on the download location. + +2. Download or clone the repository and navigate into the `java-simple-stream-benchmark` directory: + ```shell + git clone https://github.com/graalvm/graalvm-demos + cd graalvm-demos/java-simple-stream-benchmark + ``` + +3. Build the benchmark. You can manually execute `mvn package`, but there is also a `build.sh` script included for your convenience: + ```shell + ./build.sh + ``` Now you are all set to execute the benchmark and compare the results between different JVMs. -### Running the Benchmark +## Running the Benchmark To run the benchmark, you need to execute the `target/benchmarks.jar` file. You can run it with the following command: ```shell java -jar target/benchmarks.jar ``` -If you would like to run the benchmark on a different JVM, you can run it with -whatever `java` you have. However, if you just want to run it on the same JVM, -but without the GraalVM compiler, you may add the `-XX:-UseJVMCICompiler` option -into the same command: +If you would like to run the benchmark on a different JVM, you can run it with whatever `java` you have. +However, if you just want to run it on the same JVM, but without the GraalVM compiler, you may add the `-XX:-UseJVMCICompiler` option into the same command: ```shell java -XX:-UseJVMCICompiler -jar target/benchmarks.jar ``` @@ -58,7 +58,6 @@ This way, the GraalVM compiler will not be used as the JVMCI compiler and the JV ### Note about Results -The benchmark mode is `AverageTime` in nanoseconds per operation, which means -lower numbers are better. Note that the results you see can be influenced by the -hardware you are running this benchmark on, the CPU load, and other factors. +The benchmark mode is `AverageTime` in nanoseconds per operation, which means lower numbers are better. +Note that the results you see can be influenced by the hardware you are running this benchmark on, the CPU load, and other factors. Interpret them responsibly. diff --git a/docs/examples/mle-oracle.md b/docs/examples/mle-oracle.md index 3806fd535cfe..be336d69dca2 100644 --- a/docs/examples/mle-oracle.md +++ b/docs/examples/mle-oracle.md @@ -46,9 +46,9 @@ END; / ``` -Please also note the EXCEPTION clause which makes sure that the context gets dropped either way. This is important to avoid resource leakage. +Note: There is the `EXCEPTION` clause which makes sure that the context gets dropped either way. This is important to avoid resource leakage. -2. Now here's an example that shows how values can be passed between PL/SQL and MLE. As expected, the output is `49`: +2. Now here is an example that shows how values can be passed between PL/SQL and MLE. As expected, the output is `49`: ```sql SET SERVEROUTPUT ON; DECLARE @@ -139,6 +139,7 @@ END; ``` ## Type Conversions + Let us now have a closer look at conversions from Oracle types (as retrieved by SQL queries) to JavaScript types. By default, Oracle data types get automatically converted to regular, native JavaScript types, which can lead to a loss of precision. @@ -249,6 +250,7 @@ END; ``` ## Further Reading + Here is a set of resources that we recommend for further reading about MLE: - [Multilingual Engine: Executing JavaScript in Oracle Database](https://medium.com/graalvm/mle-executing-javascript-in-oracle-database-c545feb1a010) provides further insight into the MLE architecture based on GraalVM. - [MLE and the Future of Server-Side Programming in Oracle APEX](https://blogs.oracle.com/apex/mle-and-the-future-of-server-side-programming-in-oracle-apex) shows step-by-step how to set up a free Oracle Cloud account, provision a database instance and run some JavaScript code in Oracle APEX (powered by MLE). diff --git a/docs/examples/native-image-examples.md b/docs/examples/native-image-examples.md index b1412280e053..13c8d66cca8c 100644 --- a/docs/examples/native-image-examples.md +++ b/docs/examples/native-image-examples.md @@ -7,59 +7,62 @@ permalink: /examples/native-image-examples/ # Ahead-of-Time Compilation of Java and Polyglot Applications -Below are sample applications illustrating GraalVM's unique -capabilities to create self-contained executable images which can run -incredibly fast. Here you will also find a more sophisticated example displaying -GraalVM's ability to create polyglot native executables. +Below are sample applications illustrating GraalVM's unique capabilities to create self-contained executable images which can run incredibly fast. +Here you will also find a more sophisticated example displaying GraalVM's ability to create polyglot native executables. -### Preparation +## Preparation 1. Download or clone the repository and navigate into the `native-list-dir` directory: -```shell -git clone https://github.com/graalvm/graalvm-demos -cd graalvm-demos/native-list-dir -``` -There are two Java classes, but you will start by building `ListDir.java` for the -purposes of this demo. You can manually execute `javac ListDir.java`, and there is -also a `build.sh` script included for your convenience. - -Note that you can use -any JDK for compiling the Java classes. However, we refer to `javac` from GraalVM -in the build script to simplify the prerequisites so another JDK does not need to be installed. - -2. Having installed GraalVM, export the home directory as `$GRAALVM_HOME` and add `$GRAALVM_HOME/bin` -to the path, using a command-line shell for Linux: -```shell -export GRAALVM_HOME=/home/${current_user}/path/to/graalvm -``` -For macOS, use: -```shell -export GRAALVM_HOME=/Users/${current_user}/path/to/graalvm/Contents/Home -``` -Note that your paths are likely to be different depending on the download location. - -3. [Install Native Image](../reference-manual/native-image/README.md/#install-native-image) to make use of the `native-image` utility. + ```shell + git clone https://github.com/graalvm/graalvm-demos + cd graalvm-demos/native-list-dir + ``` + There are two Java classes, but you will start by building `ListDir.java` for the purposes of this demo. + You can manually execute `javac ListDir.java`, and there is also a `build.sh` script included for your convenience. + + Note that you can use any JDK for compiling the Java classes. + However, we refer to `javac` from GraalVM in the build script to simplify the prerequisites so another JDK does not need to be installed. + +2. [Download GraalVM](https://www.graalvm.org/downloads/), unzip the archive, export the GraalVM home directory as the `$JAVA_HOME` and add `$JAVA_HOME/bin` to the `PATH` environment variable: + On Linux: + ```bash + export JAVA_HOME=/home/${current_user}/path/to/graalvm + export PATH=$JAVA_HOME/bin:$PATH + ``` + On macOS: + ```bash + export JAVA_HOME=/Users/${current_user}/path/to/graalvm/Contents/Home + export PATH=$JAVA_HOME/bin:$PATH + ``` + On Windows: + ```bash + setx /M JAVA_HOME "C:\Progra~1\Java\" + setx /M PATH "C:\Progra~1\Java\\bin;%PATH%" + ``` + Note that your paths are likely to be different depending on the download location. + +3. [Install Native Image](../reference-manual/native-image/README.md/#install-native-image) by running. + ```bash + gu install native-image + ``` 4. Then execute: -```shell -./build.sh -``` + ```shell + ./build.sh + ``` The `build.sh` script creates a native executable from the Java class. Look at it in more detail: ```shell -$GRAALVM_HOME/bin/native-image ListDir +$JAVA_HOME/bin/native-image ListDir ``` -The `native-image` utility ahead-of-time compiles the `ListDir` class into a -standalone binary in the current working directory. After running the -command, the executable file `listdir` should have been produced. +The `native-image` utility ahead-of-time compiles the `ListDir` class into a standalone binary in the current working directory. +After running the command, the executable file `listdir` should have been produced. -### Running the Application +## Running the Application -To run the application, you need to either execute the `ListDir` class -as a normal Java application using `java`, or since we have a native executable -prepared, run that directly. +To run the application, you need to either execute the `ListDir` class as a normal Java application using `java`, or since we have a native executable prepared, run that directly. The `run.sh` file executes both, and times them with the `time` utility: ```shell @@ -67,8 +70,7 @@ time java ListDir $1 time ./listdir $1 ``` -To make it more interesting, pass it to a parent directory: `./run.sh ..`, where `..` is -the parent of the current directory (the one containing all the demos). +To make it more interesting, pass it to a parent directory: `./run.sh ..`, where `..` is the parent of the current directory (the one containing all the demos). Depending on the directory content you pass this script for, the output will be different than this: ```shell @@ -89,35 +91,36 @@ sys 0m0.011s ``` The performance gain of the native version is largely due to the faster startup. -### Polyglot Capabilities +## Polyglot Capabilities -You can also experiment with a more sophisticated `ExtListDir` example, -which takes advantage of GraalVM's Java and JavaScript polyglot capabilities. +You can also experiment with a more sophisticated `ExtListDir` example, which takes advantage of GraalVM's Java and JavaScript polyglot capabilities. ```shell -$GRAALVM_HOME/bin/javac ExtListDir.java +$JAVA_HOME/bin/javac ExtListDir.java ``` Building the native executable command is similar to the one above, but since the example uses JavaScript, you need to inform the `native-image` utility about that by passing the `--language:js` option. Note that it takes a bit more time because it needs to include the JavaScript support. ```shell -$GRAALVM_HOME/bin/native-image --language:js ExtListDir +$JAVA_HOME/bin/native-image --language:js ExtListDir ``` The execution is the same as in the previous example: ```shell -$ time java ExtListDir $1 -$ time ./extlistdir $1 +time java ExtListDir $1 +time ./extlistdir $1 ``` -### Profile-Guided Optimizations for High Throughput +## Profile-Guided Optimizations for High Throughput -Oracle GraalVM Enterprise Edition offers extra benefits for building native executables. These are [profile-guided optimisations (PGO)](../reference-manual/native-image/PGOEnterprise.md). As an example, a [program demonstrating Java streams](https://github.com/graalvm/graalvm-demos/blob/master/scala-examples/streams/Streams.java) will be used. +Oracle GraalVM Enterprise Edition offers extra benefits for building native executables. +These are [profile-guided optimisations (PGO)](../reference-manual/native-image/PGOEnterprise.md). +As an example, a [program demonstrating Java streams](https://github.com/graalvm/graalvm-demos/blob/master/scala-examples/streams/Streams.java) will be used. 1. Run the application with `java` to see the output: ```shell javac Streams.java -$GRAALVM_HOME/bin/native-image Streams +$JAVA_HOME/bin/native-image Streams ./streams 1000000 200 ... Iteration 20 finished in 1955 milliseconds with checksum 6e36c560485cdc01 @@ -125,14 +128,14 @@ Iteration 20 finished in 1955 milliseconds with checksum 6e36c560485cdc01 2. Build an instrumented image and run it to collect profiles: ```shell -$GRAALVM_HOME/bin/native-image --pgo-instrument Streams +$JAVA_HOME/bin/native-image --pgo-instrument Streams ./streams 1000 200 ``` Profiles collected from this run are now stored in the `default.iprof` file. Note that the profiling now runs with a much smaller data size. 3. Use the profiles gathered at the previous step to build an optimized native executable: ```shell -$GRAALVM_HOME/bin/native-image --pgo Streams +$JAVA_HOME/bin/native-image --pgo Streams ``` 4. Run that optimized native executable: diff --git a/docs/examples/polyglot-javascript-java-r.md b/docs/examples/polyglot-javascript-java-r.md index 9dd251a389d9..78672a957f83 100644 --- a/docs/examples/polyglot-javascript-java-r.md +++ b/docs/examples/polyglot-javascript-java-r.md @@ -12,54 +12,64 @@ This page describes an example of a polyglot application you can run with GraalV ### Preparation 1. Download or clone the repository and navigate into the `polyglot-javascript-java-r` directory: -```shell -git clone https://github.com/graalvm/graalvm-demos -cd graalvm-demos/polyglot-javascript-java-r -``` - -2. [Install GraalVM](/docs/getting-started/#install-graalvm) on your platform. + ```bash + git clone https://github.com/graalvm/graalvm-demos + cd graalvm-demos/polyglot-javascript-java-r + ``` + +2. [Download GraalVM](https://www.graalvm.org/downloads/), unzip the archive, export the GraalVM home directory as the `$JAVA_HOME` and add `$JAVA_HOME/bin` to the `PATH` environment variable: + On Linux: + ```bash + export JAVA_HOME=/home/${current_user}/path/to/graalvm + export PATH=$JAVA_HOME/bin:$PATH + ``` + On macOS: + ```bash + export JAVA_HOME=/Users/${current_user}/path/to/graalvm/Contents/Home + export PATH=$JAVA_HOME/bin:$PATH + ``` + On Windows: + ```bash + setx /M JAVA_HOME "C:\Progra~1\Java\" + setx /M PATH "C:\Progra~1\Java\\bin;%PATH%" + ``` + Note that your paths are likely to be different depending on the download location. 3. To run the demo, you need to enable Node.js support in GraalVM: -```shell -gu install nodejs -``` + ```bash + gu install nodejs + ``` 4. This application contains R code. The R language support is not enabled by default in GraalVM and you should add it too: -```shell -gu install R -``` + ```bash + gu install R + ``` 5. Build the benchmark. You can manually execute `npm install`, but there is also a `build.sh` script included for your convenience: -```shell -./build.sh -``` + ```bash + ./build.sh + ``` Now you are all set to run the polyglot JavaScript, Java, R application. ### Running the Application To run the application, you need to execute the `server.js` file. You can run it with the following command (or run the `run.sh` script): -```shell -$GRAALVM_HOME/bin/node --polyglot --jvm server.js +```bash +$JAVA_HOME/bin/node --polyglot --jvm server.js ``` -If you would like to run the benchmark on a different instance of Node, -you can run it with whatever `node` you have. However, presumably, the polyglot -capability will not be supported. +If you would like to run the benchmark on a different instance of Node, you can run it with whatever `node` you have. However, presumably, the polyglot capability will not be supported. Open [localhost:3000](http://localhost:3000) and see the output of the polyglot app. -Play with the source code and restart the application to see what else -you can do with the mix of JavaScript, Java, and R. +Play with the source code and restart the application to see what else you can do with the mix of JavaScript, Java, and R. ### Debugging Polyglot Applications -GraalVM also supports debugging of polyglot applications and provides a built-in -implementation of the [Chrome DevTools Protocol](../tools/chrome-debugger.md). Add the `--inspect` parameter to the command line, open the URL the application -prints at the startup in the Chrome browser, and start debugging: set breakpoints, -evaluate expressions of this app in JavaScript and R code alike, and so on. +GraalVM also supports debugging of polyglot applications and provides a built-in implementation of the [Chrome DevTools Protocol](../tools/chrome-debugger.md). +Add the `--inspect` parameter to the command line, open the URL the application prints at the startup in the Chrome browser, and start debugging: set breakpoints, evaluate expressions of this app in JavaScript and R code alike, and so on. ### Note about the Application -For brevity, this sample application contains large snippets of code -inside the strings. This is not the best approach for structuring polyglot applications, -but it is the easiest way to demonstrate polyglot capabilities in a single file. +For brevity, this sample application contains large snippets of code inside the strings. +This is not the best approach for structuring polyglot applications, but it is the easiest way to demonstrate polyglot capabilities in a single file. diff --git a/docs/getting-started/graalvm-community/container-images/graalvm-ce-container-images.md b/docs/getting-started/graalvm-community/container-images/graalvm-ce-container-images.md index a16a8e3b7014..d16d16acd800 100644 --- a/docs/getting-started/graalvm-community/container-images/graalvm-ce-container-images.md +++ b/docs/getting-started/graalvm-community/container-images/graalvm-ce-container-images.md @@ -22,7 +22,7 @@ FROM ghcr.io/graalvm/graalvm-ce:latest There are different GraalVM Community container images provided depending on the architecture and the Java version. GraalVM binaries are built for Linux, macOS, and Windows platforms on x86 64-bit systems, and for Linux on ARM 64-bit systems. -The images are multi-arch (`aarch64` or `amd64` will be pulled depending on Docker host architecture), and named per a _platform-jdk-version_ naming scheme, for example, `ghcr.io/graalvm/graalvm-ce:latest:ol8-java11-21.2.0`. +The images are multi-arch (`aarch64` or `amd64` will be pulled depending on Docker host architecture), and named per a _platform-jdk-version_ naming scheme, for example, `ghcr.io/graalvm/graalvm-ce:latest:ol8-java11-21.3.0`. A complete list can be found on the [All versions](https://github.com/orgs/graalvm/packages/container/graalvm-ce/versions) page. The images are based on Oracle Linux and has GraalVM Community downloaded, unzipped and made available. @@ -30,33 +30,33 @@ It means that Java, JavaScript, Node.js and the LLVM runtime are available out o You can start a container and enter the `bash` session with the following run command: ```shell -docker run -it --rm ghcr.io/graalvm/graalvm-ce:21.2.0 bash +docker run -it --rm ghcr.io/graalvm/graalvm-ce:21.3.0 bash ``` Check that `java`, `js` and other commands work as expected. ```shell -→ docker run -it --rm ghcr.io/graalvm/graalvm-ce:21.2.0 bash +→ docker run -it --rm ghcr.io/graalvm/graalvm-ce:21.3.0 bash bash-4.4# java -version -openjdk version "11.0.12" 2021-07-20 -OpenJDK Runtime Environment GraalVM CE 21.2.0 (build 11.0.12+6-jvmci-21.2-b06) -OpenJDK 64-Bit Server VM GraalVM CE 21.2.0 (build 11.0.12+6-jvmci-21.2-b06, mixed mode, sharing) +openjdk version "17" 2021-09-14 +OpenJDK Runtime Environment GraalVM CE 21.3.0 (build 17+35-jvmci-21.3-b03) +OpenJDK 64-Bit Server VM GraalVM CE 21.3.0 (build 17+35-jvmci-21.3-b03, mixed mode, sharing) + bash-4.4# js -version -GraalVM JavaScript (GraalVM CE Native 21.2.0) +GraalVM JavaScript (GraalVM CE Native 21.3.0) > 1 + 1 2 > quit() +> bash-4.4# lli --version -LLVM 10.0.0 (GraalVM CE Native 21.2.0) -bash-4.4# +LLVM 12.0.1 (GraalVM CE Native 21.3.0) ``` Please note that the image contains only the components immediately available in the GraalVM Community core download. -However, the [GraalVM Updater](/reference-manual/graalvm-updater/) utility is on the `PATH` and you can install the support for additional languages and runtimes like Node.js, Ruby, R, Python or WebAssembly at will. +However, the [GraalVM Updater, `gu`](../../../reference-manual/graalvm-updater.md), utility is included in the container image and may be used to install additional languages and runtimes like Node.js, Ruby, R, Python or WebAssembly. -However, the [GraalVM Updater, `gu`](/reference-manual/graalvm-updater/), utility is included in the container image and may be used to install additional languages and runtimes like Node.js, Ruby, R, Python or WebAssembly. For example, the following command installs the Ruby support (the output below is truncated for brevity): ```shell -docker run -it --rm ghcr.io/graalvm/graalvm-ce:21.2.0 bash +docker run -it --rm ghcr.io/graalvm/graalvm-ce:21.3.0 bash bash-4.4# gu install ruby Downloading: Component catalog Processing component archive: Component ruby @@ -68,13 +68,13 @@ Downloading: Component ruby Here is a sample command that maps the `/absolute/path/to/directory/no/trailing/slash` directory from the host system to the `/path/inside/container` inside the container. ```shell -docker run -it --rm -v /absolute/path/to/directory/no/trailing/slash:/path/inside/container ghcr.io/graalvm/graalvm-ce:21.2.0 bash +docker run -it --rm -v /absolute/path/to/directory/no/trailing/slash:/path/inside/container ghcr.io/graalvm/graalvm-ce:21.3.0 bash ``` -If you want to create Docker images that contain GraalVM with Ruby, R, or Python, you can use a Dockerfile like the example below, which uses `ghcr.io/graalvm/graalvm-ce:21.2.0` as the base image, installs the Ruby support using the `gu` utility, then creates and runs a sample Ruby program. +If you want to create Docker images that contain GraalVM with Ruby, R, or Python, you can use a Dockerfile like the example below, which uses `ghcr.io/graalvm/graalvm-ce:21.3.0` as the base image, installs the Ruby support using the `gu` utility, then creates and runs a sample Ruby program. ```shell -FROM ghcr.io/graalvm/graalvm-ce:21.2.0 +FROM ghcr.io/graalvm/graalvm-ce:21.3.0 RUN gu install ruby WORKDIR /workdir RUN echo 'puts "Hello from Ruby!\nVersion: #{RUBY_DESCRIPTION}"' > app.rb @@ -88,5 +88,5 @@ docker build -t ruby-demo . ... docker run -it --rm ruby-demo Hello from Ruby! -Version: truffleruby 21.2.0, like ruby 2.7.3, GraalVM CE Native [x86_64-darwin] +Version: truffleruby 21.3.0, like ruby 2.7.4, GraalVM CE Native [x86_64-darwin] ``` diff --git a/docs/getting-started/graalvm-community/get-started-graalvm-community.md b/docs/getting-started/graalvm-community/get-started-graalvm-community.md index 4945739eea13..ca70038a5ee2 100644 --- a/docs/getting-started/graalvm-community/get-started-graalvm-community.md +++ b/docs/getting-started/graalvm-community/get-started-graalvm-community.md @@ -14,18 +14,18 @@ GraalVM's polyglot capabilities make it possible to mix multiple programming lan Here you will find information about installing GraalVM Community Edition, running basic applications with it, and adding support for accompanying features. Further, you will learn about the polyglot capabilities of GraalVM and see how to build platform-specific native executables of JVM-based applications. -If you are new to GraaVM, we recommend starting with [Introduction to GraalVM](/docs/introduction/), where you will find information about GraalVM's architecture, distributions available, supported platforms, core and additional features, and much more. +If you are new to GraaVM, we recommend starting with [Introduction to GraalVM](../../introduction.md), where you will find information about GraalVM's architecture, distributions available, supported platforms, core and additional features, and much more. -If you have GraalVM already installed and have experience using it, you can skip this getting started guide and proceed to the in-depth [Reference Manuals](/reference-manual/). +If you have GraalVM already installed and have experience using it, you can skip this getting started guide and proceed to the in-depth [Reference Manuals](../../reference-manual/reference-manuals.md). ## Install GraalVM Getting GraalVM installed and ready-to-go should take a few minutes. Choose the operating system and proceed to the installation steps: -* [Linux](/docs/getting-started/linux/) -* [Linux AArch64](/docs/getting-started/linux-aarch64/) -* [macOS](/docs/getting-started/macos/) -* [Windows](/docs/getting-started/windows/) +* [Linux](linux.md) +* [Linux AArch64](linux-aarch64.md) +* [macOS](macos.md) +* [Windows](windows.md) ## Start Running Applications @@ -42,14 +42,15 @@ GraalVM's `/bin` directory is similar to that of a standard JDK, but includes a Check the versions of the runtimes provided by default: ```shell java -version -openjdk version "11.0.12" 2021-07-20 -OpenJDK Runtime Environment GraalVM CE 21.2.0 (build 11.0.12+6-jvmci-21.2-b06) -OpenJDK 64-Bit Server VM GraalVM CE 21.2.0 (build 11.0.12+6-jvmci-21.2-b06, mixed mode, sharing) +openjdk version "17" 2021-09-14 +OpenJDK Runtime Environment GraalVM CE 21.3.0 (build 17+35-jvmci-21.3-b03) +OpenJDK 64-Bit Server VM GraalVM CE 21.3.0 (build 17+35-jvmci-21.3-b03, mixed mode, sharing) + js -version -GraalVM JavaScript (GraalVM CE Native 21.2.0) +GraalVM JavaScript (GraalVM CE Native 21.3.0) lli --version -LLVM 10.0.0 (GraalVM CE Native 21.2.0) +LLVM 12.0.1 (GraalVM CE Native 21.3.0) ``` Further below you will find information on how to add other optionally available GraalVM runtimes including Node.js, Ruby, R, Python, and WebAssembly. @@ -73,10 +74,10 @@ java HelloWorld Hello World! ``` -You can find a collection of larger Java examples on the [Examples Applications](/examples/) page. +You can find a collection of larger Java examples on the [Examples Applications](../../examples/examples.md) page. For more information on the GraalVM -compiler, go to [Compiler](/reference-manual/compiler/). -For more extensive documentation on running Java, proceed to [JVM Languages](/reference-manual/java/). +compiler, go to [Compiler](../../reference-manual/compiler.md). +For more extensive documentation on running Java, proceed to [JVM Languages](../../reference-manual/java/README.md). ## Run JavaScript and Node.js @@ -91,17 +92,20 @@ GraalVM also supports running Node.js applications. Node.js support is not installed by default, but can be easily added with GraalVM Updater: ```shell gu install nodejs -node -v -v14.16.1 +``` +```shell +$JAVA_HOME/bin/node -v +v14.17.6 ``` More than 100,000 npm packages are regularly tested and are compatible with GraalVM, including modules like express, react, async, request, browserify, grunt, mocha, and underscore. To install a Node.js module, use the `npm` executable from the `/bin` folder, which is installed together with `node`. The `npm` command is equivalent to the default Node.js command and supports all Node.js APIs. -Install the `colors` and `ansispan` modules using `npm install`. After the modules are installed, you can use them from your application. +Install the modules `colors`, `ansispan`, and `express` using `npm install`. +After the modules are installed, you can use them from your application. ```shell -npm install colors ansispan +$JAVA_HOME/bin/npm install colors ansispan express ``` Use the following code snippet and save it as the `app.js` file in the same directory where you installed the Node.js modules: @@ -120,11 +124,10 @@ setTimeout(function() { console.log("DONE!"); process.exit(); }, 2000); Run _app.js_ on GraalVM Enterprise using the `node` command: ```shell -node app.js +$JAVA_HOME/bin/node app.js ``` -For more detailed documentation and information on compatibility with Node.js, -proceed to [JavaScript and Node.js](/reference-manual/js/). +For more detailed documentation and information on compatibility with Node.js, proceed to [JavaScript and Node.js](../../reference-manual/js/README.md). ## Run LLVM Languages @@ -154,12 +157,12 @@ $LLVM_TOOLCHAIN/clang hello.c -o hello lli hello ``` -For in-depth documentation and more examples of running LLVM bitcode on GraalVM, go to [LLVM Languages](/reference-manual/llvm/). +For in-depth documentation and more examples of running LLVM bitcode on GraalVM, go to [LLVM Languages](../../reference-manual/llvm/README.md). ## Run Python With GraalVM you can run Python applications in the Python 3 runtime environment. -The support is not available by default, but you can quickly add it to GraalVM using the [GraalVM Updater](/reference-manual/graalvm-updater/) tool: +The support is not available by default, but you can quickly add it to GraalVM using the [GraalVM Updater](../../reference-manual/graalvm-updater.md) tool: ```shell gu install python ``` @@ -173,12 +176,12 @@ graalpython >>> exit() ``` -More examples and additional information on Python support in GraalVM can be found in the [Python reference manual](/reference-manual/python/). +More examples and additional information on Python support in GraalVM can be found in the [Python reference manual](../../reference-manual/python/README.md). ## Run Ruby GraalVM provides a high-performance Ruby runtime environment including the `gem` command that allows you to interact with RubyGems, Ruby Bundler, and much more. -The Ruby runtime is not available by default in GraalVM, but can be easily added using the [GraalVM Updater](/reference-manual/graalvm-updater/) tool: +The Ruby runtime is not available by default in GraalVM, but can be easily added using the [GraalVM Updater](../../reference-manual/graalvm-updater.md) tool: ```shell gu install ruby ``` @@ -189,7 +192,7 @@ ruby [options] program.rb ``` GraalVM Ruby runtime environment uses the -[same options as the standard implementation of Ruby](/reference-manual/ruby/Options/), +[same options as the standard implementation of Ruby](../../reference-manual/ruby/options.md), with some additions. For example: ```shell gem install chunky_png @@ -197,12 +200,12 @@ ruby -r chunky_png -e "puts ChunkyPNG::Color.to_hex(ChunkyPNG::Color('mintcream #f5fffa80 ``` -More examples and in-depth documentation can be found in the [Ruby reference manual](/reference-manual/ruby/). +More examples and in-depth documentation can be found in the [Ruby reference manual](../../reference-manual/ruby/README.md). ## Run R GraalVM provides a GNU-compatible environment to run R programs directly or in the REPL mode. -Although the R language support is not available by default, you can add it to GraalVM using the [GraalVM Updater](/reference-manual/graalvm-updater/) tool: +Although the R language support is not available by default, you can add it to GraalVM using the [GraalVM Updater](../../reference-manual/graalvm-updater.md) tool: ```shell gu install R ``` @@ -217,12 +220,12 @@ R version 4.0.3 (FastR) [1] 2 ``` -More examples and in-depth documentation can be found in the [R reference manual](/reference-manual/r/). +More examples and in-depth documentation can be found in the [R reference manual](../../reference-manual/r/README.md). ## Run WebAssembly With GraalVM you can run programs compiled to WebAssembly. -The support is not available by default, but you can add it to GraalVM using the [GraalVM Updater](/reference-manual/graalvm-updater/) tool: +The support is not available by default, but you can add it to GraalVM using the [GraalVM Updater](../../reference-manual/graalvm-updater.md) tool: ```shell gu install wasm ``` @@ -256,7 +259,7 @@ Then you can run the compiled WebAssembly binary on GraalVM as follows: wasm --Builtins=wasi_snapshot_preview1 floyd.wasm ``` -More details can be found in the [WebAssembly reference manual](/reference-manual/wasm/). +More details can be found in the [WebAssembly reference manual](../../reference-manual/wasm/README.md). ## Combine Languages @@ -265,12 +268,12 @@ To enable interoperability, GraalVM provides the `--polyglot` flag. For example, running `js --jvm --polyglot example.js` executes `example.js` in a polyglot context. If the program calls any code in other supported languages, GraalVM executes that code in the same runtime as the `example.js` application. -For more information on running polyglot applications, see [Polyglot Programming](/reference-manual/polyglot-programming/). +For more information on running polyglot applications, see [Polyglot Programming](../../reference-manual/polyglot-programming.md). ## Native Images With GraalVM you can compile Java bytecode into a platform-specific, self-contained, native executable - a native image - to achieve faster startup and smaller footprint for your application. -The [Native Image](/reference-manual/native-image/) functionality is not available by default, but can be easily installed with the [GraalVM Updater](/reference-manual/graalvm-updater/) tool: +The [Native Image](../../reference-manual/native-image/README.md) functionality is not available by default, but can be easily installed with the [GraalVM Updater](../../reference-manual/graalvm-updater.md) tool: ```shell gu install native-image ``` @@ -285,7 +288,7 @@ public class HelloWorld { } ``` -> Note: For compilation `native-image` depends on the local toolchain. Make sure your system meets the [prerequisites](/reference-manual/native-image/#prerequisites). +> Note: For compilation `native-image` depends on the local toolchain. Make sure your system meets the [prerequisites](../../reference-manual/native-image/README.md#prerequisites). Compile _HelloWorld.java_ to bytecode and then build a native image: ```shell @@ -300,7 +303,7 @@ Invoking it executes the natively compiled code of the `HelloWorld` class as fol Hello, World! ``` -More detailed documentation on this innovative technology is available in the [Native Image reference manual](/reference-manual/native-image/). +More detailed documentation on this innovative technology is available in the [Native Image reference manual](../../reference-manual/native-image/README.md). ## Polyglot Capabilities of Native Images @@ -336,7 +339,7 @@ javac PrettyPrintJSON.java native-image --language:js --initialize-at-build-time PrettyPrintJSON ``` The native image generatation will take several minutes as it does not just build the `PrettyPrintJSON` class, but also builds JavaScript. -Additionally, the image building requires large amounts of physical memory, especially if you build an image with the [Truffle language implementation framework](/graalvm-as-a-platform/language-implementation-framework/) included, which is the case here. +Additionally, the image building requires large amounts of physical memory, especially if you build an image with the [Truffle language implementation framework](../../../truffle/docs/README.md) included, which is the case here. The resulting executable can now perform JSON pretty-printing: ```shell @@ -384,14 +387,14 @@ sys 0m0.016s ## What to Read Next ### New Users -Since this guide is intended mainly for users new to GraalVM, or users who are familiar with GraalVM but may have little experience using it, please consider investigating more complex [Example Applications](/examples/). -We also recommend checking our [GraalVM Team Blog](/blog/). +Since this guide is intended mainly for users new to GraalVM, or users who are familiar with GraalVM but may have little experience using it, please consider investigating more complex [Example Applications](../../examples/examples.md). +We also recommend checking our [GraalVM Team Blog](https://medium.com/graalvm). ### Advanced Users -If you are mostly interested in GraalVM support for a specific language, or want more in-depth details about GraalVM's diverse technologies, proceed to [Reference Manuals](/reference-manual/). +If you are mostly interested in GraalVM support for a specific language, or want more in-depth details about GraalVM's diverse technologies, proceed to [Reference Manuals](../../reference-manual/reference-manuals.md). -If you are looking for the tooling support GraalVM offers, proceed to [Debugging and Monitoring Tools](/tools/). +If you are looking for the tooling support GraalVM offers, proceed to [Debugging and Monitoring Tools](../../tools/tools.md). -If you are considering GraalVM as a platform for your future language or tool implementation, go to [GraalVM as a Platform](/graalvm-as-a-platform/language-implementation-framework/). +If you are considering GraalVM as a platform for your future language or tool implementation, go to [GraalVM as a Platform](../../../truffle/docs/README.md). -You can find information on GraalVM's security model in the [Security Guide](/security-guide/), and rich API documentation in [GraalVM SDK Javadoc](https://www.graalvm.org/sdk/javadoc/) and [Truffle Javadoc](https://www.graalvm.org/truffle/javadoc/). +You can find information on GraalVM's security model in the [Security Guide](../../security/security-guide.md), and rich API documentation in [GraalVM SDK Javadoc](https://www.graalvm.org/sdk/javadoc/) and [Truffle Javadoc](https://www.graalvm.org/truffle/javadoc/). diff --git a/docs/getting-started/graalvm-community/linux-aarch64.md b/docs/getting-started/graalvm-community/linux-aarch64.md index e4fb8d221c09..21a1123332a6 100644 --- a/docs/getting-started/graalvm-community/linux-aarch64.md +++ b/docs/getting-started/graalvm-community/linux-aarch64.md @@ -7,15 +7,13 @@ permalink: /docs/getting-started/linux-aarch64/ # Installation on Linux ARM64 systems -As of version 21.0, we provide GraalVM Community Edition for Linux on ARM 64-bit system, based on OpenJDK 11 for AArch64 architecture. +As of version 21.0, we provide GraalVM Community Edition for Linux on ARM 64-bit system, based on OpenJDK 11 and OpenJDK 17 for AArch64 architecture. This distribution can be installed on Linux systems for AArch64 CPU architecture. -Note: The base GraalVM Community distribution including all components is **experimental** on Linux ARM 64-bit systems. - You can install the GraalVM distribution for Linux ARM64 systems from an archive file (_.tar.gz_). This allows you to install GraalVM for the current user into any location, without affecting other JDK installations. -1. Navigate to the [GraalVM Releases repository on GitHub](https://github.com/graalvm/graalvm-ce-builds/releases). Depending on the workload, select Java 11 or 16 based distribution for the Linux AArch64 architecture, and download. +1. Navigate to the [GraalVM Releases repository on GitHub](https://github.com/graalvm/graalvm-ce-builds/releases). Select Java 11 or 17 based distribution for the Linux AArch64 architecture, and download. 2. Change the directory to the location where you want to install GraalVM, then move the _.tar.gz_ archive to it. 3. Unzip the archive: ```shell @@ -38,6 +36,6 @@ For Oracle GraalVM Enterprise Edition users, find the installation instructions ## Supported Functionalities -The 64-bit GraalVM Community distribution for Linux platforms includes OpenJDK with the GraalVM compiler enabled, the [GraalVM Updater, `gu`](/reference-manual/graalvm-updater/), tool, the JavaScript runtime, and some developer tools (e.g., Chrome inspector based debugger, Visual VM). -Support for [Native Image](/reference-manual/native-image/), Node.js, LLVM and WebAssembly runtimes can be installed with `gu`. +The 64-bit GraalVM Community distribution for Linux platforms includes OpenJDK with the GraalVM compiler enabled, the [GraalVM Updater, `gu`](../../reference-manual/graalvm-updater.md), tool, the JavaScript runtime, and some developer tools (e.g., Chrome inspector based debugger, Visual VM). +Support for [Native Image](../../reference-manual/native-image/README.md), Node.js, LLVM and WebAssembly runtimes can be installed with `gu`. Runtimes for Python, FastR, and Ruby languages are not available in this distribution yet. diff --git a/docs/getting-started/graalvm-community/linux.md b/docs/getting-started/graalvm-community/linux.md index 8b152d3abfda..2ac721ed2b99 100644 --- a/docs/getting-started/graalvm-community/linux.md +++ b/docs/getting-started/graalvm-community/linux.md @@ -9,7 +9,7 @@ permalink: /docs/getting-started/linux/ Follow these steps to install GraalVM Community Edition on the Linux operating system. -1. Navigate to the [GraalVM Releases repository on GitHub](https://github.com/graalvm/graalvm-ce-builds/releases). Depending on the workload, select Java 11 based or Java 8 based distribution for the Linux AMD64 architecture, and download. +1. Navigate to the [GraalVM Releases repository on GitHub](https://github.com/graalvm/graalvm-ce-builds/releases). Select Java 11 based or Java 17 based distribution for the Linux AMD64 architecture, and download. 2. Change the directory to the location where you want to install GraalVM, then move the _.tar.gz_ archive to it. 3. Unzip the archive: ```shell @@ -36,20 +36,18 @@ The base distribution of GraalVM Community Edition for Linux (AMD64) platforms i The base installation can be extended with: Tools/Utilities: -* [Native Image](/reference-manual/native-image/) -- a technology to compile an application ahead-of-time into a native executable -* [LLVM toolchain](/reference-manual/llvm/Compiling/#llvm-toolchain-for-compiling-cc) -- a set of tools and APIs for compiling native programs to bitcode that can be executed with on the GraalVM runtime -* [Java on Truffle](/reference-manual/java-on-truffle/) -- a Java Virtual Machine implementation based on a Truffle interpreter for GraalVM +* [Native Image](../../reference-manual/native-image/README.md) -- a technology to compile an application ahead-of-time into a native executable +* [LLVM toolchain](../../reference-manual/llvm/Compiling.md#llvm-toolchain-for-compiling-cc) -- a set of tools and APIs for compiling native programs to bitcode that can be executed with on the GraalVM runtime Runtimes: -* [Node.js](/reference-manual/js/) -- Node.js 14.16.1 compatible -* [Python](/reference-manual/python/) -- Python 3.8.5 compatible -* [Ruby](/reference-manual/ruby/) -- Ruby 2.7.2 compatible -* [R](/reference-manual/r/) -- GNU R 4.0.3 compatible -* [Wasm](/reference-manual/wasm/) -- WebAssembly (Wasm) +* [Java on Truffle](../../reference-manual/java-on-truffle/README.md) -- a Java Virtual Machine implementation based on a Truffle interpreter for GraalVM +* [Node.js](../../reference-manual/js/README.md) -- Node.js v14.17.6 compatible +* [Python](../../reference-manual/python/README.md) -- Python 3.8.5 compatible +* [Ruby](../../reference-manual/ruby/README.md) -- Ruby 2.7.2 compatible +* [R](/../../reference-manual/r/README.md) -- GNU R 4.0.3 compatible +* [Wasm](../../reference-manual/wasm/README.md) -- WebAssembly (Wasm) ​ These runtimes are not part of the GraalVM Community base distribution and must be installed separately. -To assist a user with installation, GraalVM includes -**GraalVM Updater**, a command line utility to install and manage additional -functionalities. Proceed to the [installation steps](/reference-manual/graalvm-updater/#component-installation){:target="_blank"} -to add any necessary language runtime or utility from above to GraalVM. +To assist a user with installation, GraalVM includes **GraalVM Updater**, a command line utility to install and manage additional functionalities. +Proceed to the [installation steps](../../reference-manual/graalvm-updater.md#component-installation) to add any necessary language runtime or utility from above to GraalVM. diff --git a/docs/getting-started/graalvm-community/macos.md b/docs/getting-started/graalvm-community/macos.md index 4828d64b6229..3a83017b0165 100644 --- a/docs/getting-started/graalvm-community/macos.md +++ b/docs/getting-started/graalvm-community/macos.md @@ -10,14 +10,13 @@ permalink: /docs/getting-started/macos/ GraalVM Community Edition can be installed for a single user and administrator privileges are not required. However, if GraalVM is meant to become a default JDK, administrator privileges are required. -GraalVM Community Edition does not provide the installation wizard, unlike OpenJDK -distributions for macOS that come with the _.dmg_ download. +GraalVM Community Edition does not provide the installation wizard, unlike OpenJDK distributions for macOS that come with the _.dmg_ download. It can be installed from an archive file (_.tar.gz_). Note that in macOS, the JDK installation path is: `/Library/Java/JavaVirtualMachines//Contents/Home`. Follow these steps to install GraalVM Community on the macOS operating system: -1. Navigate to [GraalVM Releases repository on GitHub](https://github.com/graalvm/graalvm-ce-builds/releases). Depending on the workload, select Java 11 based or Java 8 based distribution for macOS, and download. +1. Navigate to [GraalVM Releases repository on GitHub](https://github.com/graalvm/graalvm-ce-builds/releases). Select Java 11 based or Java 17 based distribution for macOS, and download. 2. Unzip the archive. ```shell tar -xzf graalvm-ce-java-darvin-amd64-.tar.gz @@ -56,7 +55,7 @@ sudo xattr -r -d com.apple.quarantine /path/to/GRAALVM_HOME #### On JAVA_HOME Command The information property file, _Info.plist_, is in the top level _Contents_ folder. -This means that GraalVM Enterprise participates in the macOS-specific `/usr/libexec/java_home` mechanism. Depending on other JDK 8 installation(s) available, it is now possible that `/usr/libexec/java_home -v1.8` returns `/Library/Java/JavaVirtualMachines//Contents/Home`. +This means that GraalVM Enterprise participates in the macOS-specific `/usr/libexec/java_home` mechanism. Depending on other JDK installation(s) available, it is now possible that `/usr/libexec/java_home -v1.8` returns `/Library/Java/JavaVirtualMachines//Contents/Home`. You can run `/usr/libexec/java_home -v1.8 -V` to see the complete list of 1.8 JVMs available to the `java_home` command. This command sorts the JVMs in decreasing version order and chooses the top one as the default for the specified version. Within a specific version, the sort order appears to be stable but is unspecified. @@ -66,20 +65,18 @@ The base distribution of GraalVM Community Edition for macOS includes OpenJDK wi The base installation can be extended with: Tools/Utilities: -* [Native Image](/reference-manual/native-image/) -- a technology to compile an application ahead-of-time into a native executable -* [LLVM toolchain](/reference-manual/llvm/Compiling/#llvm-toolchain-for-compiling-cc) -- a set of tools and APIs for compiling native programs to bitcode that can be executed with on the GraalVM runtime -* [Java on Truffle](/reference-manual/java-on-truffle/) -- a Java Virtual Machine implementation based on a Truffle interpreter for GraalVM +* [Native Image](../../reference-manual/native-image/README.md) -- a technology to compile an application ahead-of-time into a native executable +* [LLVM toolchain](../../reference-manual/llvm/Compiling.md#llvm-toolchain-for-compiling-cc) -- a set of tools and APIs for compiling native programs to bitcode that can be executed with on the GraalVM runtime Runtimes: -* [Node.js](/reference-manual/js/) -- Node.js 14.16.1 compatible -* [Python](/reference-manual/python/) -- Python 3.8.5 compatible -* [Ruby](/reference-manual/ruby/) -- Ruby 2.7.2 compatible -* [R](/reference-manual/r/) -- GNU R 4.0.3 compatible -* [Wasm](/reference-manual/wasm/) -- WebAssembly (Wasm) +* [Java on Truffle](../../reference-manual/java-on-truffle/README.md) -- a Java Virtual Machine implementation based on a Truffle interpreter for GraalVM +* [Node.js](../../reference-manual/js/README.md) -- Node.js v14.17.6 compatible +* [Python](../../reference-manual/python/README.md) -- Python 3.8.5 compatible +* [Ruby](../../reference-manual/ruby/README.md) -- Ruby 2.7.2 compatible +* [R](/../../reference-manual/r/README.md) -- GNU R 4.0.3 compatible +* [Wasm](../../reference-manual/wasm/README.md) -- WebAssembly (Wasm) ​ These runtimes are not part of the GraalVM Community base distribution and must be installed separately. -To assist a user with installation, GraalVM includes -**GraalVM Updater**, a command line utility to install and manage additional -functionalities. Proceed to the [installation steps](/reference-manual/graalvm-updater/#component-installation){:target="_blank"} -to add any necessary language runtime or utility from above to GraalVM. +To assist a user with installation, GraalVM includes **GraalVM Updater**, a command line utility to install and manage additional functionalities. +Proceed to the [installation steps](../../reference-manual/graalvm-updater.md#component-installation) to add any necessary language runtime or utility from above to GraalVM. diff --git a/docs/getting-started/graalvm-community/windows.md b/docs/getting-started/graalvm-community/windows.md index 75bd7134e958..6663feb6c9aa 100644 --- a/docs/getting-started/graalvm-community/windows.md +++ b/docs/getting-started/graalvm-community/windows.md @@ -10,7 +10,7 @@ permalink: /docs/getting-started/windows/ You can install GraalVM Community Edition on the Windows operating system from an archive file (_zip_). Follow these steps: -1. Navigate to the [GraalVM Releases repository on GitHub](https://github.com/graalvm/graalvm-ce-builds/releases). Depending on the workload, select Java 11 based or Java 8 based distribution for Windows, and download. +1. Navigate to the [GraalVM Releases repository on GitHub](https://github.com/graalvm/graalvm-ce-builds/releases). Select Java 11 based or Java 17 based distribution for Windows, and download. 2. Change the directory to the location where you want to install GraalVM, then move the _.zip_ archive file to it. 3. Unzip the archive to your file system. 4. There can be multiple JDKs installed on the machine. The next step is to configure the runtime environment. Setting environment variables via the command line will work the same way for Windows 7, 8 and 10. @@ -39,16 +39,17 @@ To run GraalVM Community Edition based on OpenJDK 8u292 on a Windows platform, t ## Supported Functionalities -The GraalVM Community distribution for Windows platforms includes OpenJDK with the GraalVM compiler enabled, the [GraalVM Updater](/reference-manual/graalvm-updater/) tool to install additional functionalities, the JavaScript runtime, and the developer tools (e.g., Chrome inspector based debugger, Profiler, etc.). -Currently, the GraalVM environment on Windows can be extended with [Native Image](/reference-manual/native-image/), [Java on Trufle](/reference-manual/java-on-truffle/), WebAssembly, and Node.js support. +The GraalVM Community distribution for Windows platforms includes OpenJDK with the GraalVM compiler enabled, the [GraalVM Updater](../../reference-manual/graalvm-updater.md) tool to install additional functionalities, the JavaScript runtime, and the developer tools (e.g., Chrome inspector based debugger, Profiler, etc.). +Currently, the GraalVM environment on Windows can be extended with [Native Image](../../reference-manual/native-image/README.md), [Java on Trufle](../../reference-manual/java-on-truffle/README.md), WebAssembly, and Node.js support. ## Prerequisites for Using Native Image on Windows -To make use of Native Image on Windows, observe the following recommendations. -The required Microsoft Visual C++ (MSVC) version depends on the JDK version that GraalVM is based on. -For GraalVM based on JDK 8, you will need MSVC 2010 SP1 version. The recommended installation method is using Microsoft Windows SDK 7.1: -1. Download the SDK file `GRMSDKX_EN_DVD.iso` for from [Microsoft](https://www.microsoft.com/en-gb/download). -2. Mount the image by opening `F:\Setup\SDKSetup.exe` directly. +On Windows, Native Image requires Visual Studio Code and Microsoft Visual C++(MSVC). +You can use Visual Studio 2017 version 15.9 or later. +There are two installation options: +- Install the Visual Studio Code Build Tools with the Windows 10 SDK +- Install Visual Studio Code with the Windows 10 SDK -For GraalVM distribution based on JDK 11, you will need MSVC 2017 15.5.5 or later version. +The last prerequisite is the proper [Developer Command Prompt](https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=vs-2019#developer_command_prompt_shortcuts) for your version of [Visual Studio](https://visualstudio.microsoft.com/vs/). +On Windows the `native-image` tool only works when it is executed from the **x64 Native Tools Command Prompt**. -The last prerequisite, common for both distributions, is the proper [Developer Command Prompt](https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=vs-2019#developer_command_prompt_shortcuts) for your version of [Visual Studio](https://visualstudio.microsoft.com/vs/). On Windows the `native-image` tool only works when it is executed from the **x64 Native Tools Command Prompt**. +Step by step instructions on installing Visual Studio Build Tools and Windows 10 SDK, and starting using Native Image can be found [here](https://medium.com/graalvm/using-graalvm-and-native-image-on-windows-10-9954dc071311). diff --git a/docs/getting-started/graalvm-enterprise/get-started-graalvm-enterprise.md b/docs/getting-started/graalvm-enterprise/get-started-graalvm-enterprise.md index 24c251a1b064..d96d8bbaab89 100644 --- a/docs/getting-started/graalvm-enterprise/get-started-graalvm-enterprise.md +++ b/docs/getting-started/graalvm-enterprise/get-started-graalvm-enterprise.md @@ -8,10 +8,10 @@ permalink: /getting-started/ Here you will find information about downloading and installing GraalVM Enterprise, running basic applications with it, and adding support for its accompanying features. Further, you will learn about the polyglot capabilities of GraalVM Enterprise and see how to build platform-specific native executables of JVM-based applications. -If you are new to GraalVM Enterprise or have little experience using it, we recommend starting with the [GraalVM Enterprise Overview](https://docs.oracle.com/en/graalvm/enterprise/21/docs/overview/architecture/) page. +If you are new to GraalVM Enterprise or have little experience using it, we recommend starting with the [GraalVM Enterprise Overview](../../enterprise-overview/architecture-overview.md) page. There you will find information about GraalVM Enterprise's architecture, the distributions available, supported platforms, licensing and support, core and additional features, and much more. -If you have GraalVM Enterprise already installed and have experience using it, you can skip this getting started guide and proceed to the in-depth [Reference Manuals](/reference-manual/). +If you have GraalVM Enterprise already installed and have experience using it, you can skip this getting started guide and proceed to the in-depth [Reference Manuals](../../reference-manual/reference-manuals.md). ## Download GraalVM Enterprise @@ -25,11 +25,11 @@ You can get Oracle GraalVM Enterprise Edition by: Getting GraalVM Enterprise installed and ready-to-go should take a few minutes. Choose your operating system and proceed to the installation steps for your specific platform: -* [Linux](/getting-started/installation-linux/) -* [Linux ARM64](/getting-started/installation-linux-aarch64/) -* [Oracle Linux](/getting-started/oci/compute-instances/) -* [macOS](/getting-started/installation-macos/) -* [Windows](/getting-started/installation-windows/) +* [Linux](installation-linux.md) +* [Linux ARM64](installation-linux-aarch64.md) +* [Oracle Linux](oci/compute-instances.md) +* [macOS](installation-macos.md) +* [Windows](installation-windows.md) ## Start Running Applications @@ -45,15 +45,15 @@ GraalVM Enterprise's `/bin` directory is similar to that of a standard JDK, but Check the versions of the runtimes provided by default: ```shell -java version "11.0.12" 2021-07-20 LTS -Java(TM) SE Runtime Environment GraalVM EE 21.2.0 (build 11.0.12+8-LTS-jvmci-21.2-b06) -Java HotSpot(TM) 64-Bit Server VM GraalVM EE 21.2.0 (build 11.0.12+8-LTS-jvmci-21.2-b06, mixed mode, sharing) +java version "11.0.13" 2021-10-19 LTS +Java(TM) SE Runtime Environment GraalVM EE 21.3.0 (build 11.0.13+9-LTS-jvmci-21.3-b03) +Java HotSpot(TM) 64-Bit Server VM GraalVM EE 21.3.0 (build 11.0.13+9-LTS-jvmci-21.3-b03, mixed mode, sharing) js -version -GraalVM JavaScript (GraalVM EE Native 21.2.0) +GraalVM JavaScript (GraalVM EE Native 21.3.0) lli --version -LLVM 10.0.0 (GraalVM EE Native 21.2.0) +LLVM 12.0.1 (GraalVM EE Native 21.3.0) ``` Further below you will find information on how to add other optionally available GraalVM Enterprise runtimes including Node.js, Ruby, R, Python, and WebAssembly. @@ -78,9 +78,9 @@ java HelloWorld Hello World! ``` -You can find a collection of larger Java examples on the [Examples Applications](/examples/) page. -For more information on the GraalVM compiler, go to [Compiler](/reference-manual/compiler/). -For more extensive documentation on running Java, proceed to [JVM Languages](/reference-manual/java/). +You can find a collection of larger Java examples on the [Examples Applications](../../examples/examples.md) page. +For more information on the GraalVM compiler, go to [Compiler](../../reference-manual/compiler.md). +For more extensive documentation on running Java, proceed to [JVM Languages](../../reference-manual/java/README.md). ### JavaScript and Node.js GraalVM Enterprise can execute plain JavaScript code, both in REPL mode and by executing script files directly: @@ -94,18 +94,20 @@ GraalVM Enterprise also supports running Node.js applications. Node.js support is not installed by default, but can be easily added with GraalVM Updater: ```shell gu install nodejs -node -v -v15.12.0 +``` +```shell +$JAVA_HOME/bin/node -v +v14.17.6 ``` More than 100,000 npm packages are regularly tested and are compatible with GraalVM Enterprise, including modules like express, react, async, request, browserify, grunt, mocha, and underscore. To install a Node.js module, use the `npm` executable from the `/bin` folder, which is installed together with `node`. The `npm` command is equivalent to the default Node.js command and supports all Node.js APIs. -Install the `colors` and `ansispan` modules using `npm install`. +Install the modules `colors`, `ansispan`, and `express` using `npm install`. After the modules are installed, you can use them from your application. ```shell -npm install colors ansispan +$JAVA_HOME/bin/npm install colors ansispan express ``` Use the following code snippet and save it as the `app.js` file in the same directory where you installed the Node.js modules: @@ -124,10 +126,10 @@ setTimeout(function() { console.log("DONE!"); process.exit(); }, 2000); Run _app.js_ on GraalVM Enterprise using the `node` command: ```shell -node app.js +$JAVA_HOME/bin/node app.js ``` -For more detailed documentation and information on compatibility with Node.js, proceed to [JavaScript and Node.js](/reference-manual/js/). +For more detailed documentation and information on compatibility with Node.js, proceed to [JavaScript and Node.js](../../reference-manual/js/README.md). ### LLVM Languages @@ -161,12 +163,12 @@ $LLVM_TOOLCHAIN/clang hello.c -o hello lli hello ``` -For in-depth documentation and more examples of running LLVM bitcode on GraalVM Enterprise, go to [LLVM Languages](/reference-manual/llvm/). +For in-depth documentation and more examples of running LLVM bitcode on GraalVM Enterprise, go to [LLVM Languages](../../reference-manual/llvm/README.md). ### Python With GraalVM Enterprise you can run Python applications in the Python 3 runtime environment. -The support is not available by default, but you can quickly add it to GraalVM using the [GraalVM Updater](/reference-manual/graalvm-updater/) tool: +The support is not available by default, but you can quickly add it to GraalVM using the [GraalVM Updater](../../reference-manual/graalvm-updater.md) tool: ```shell gu install python ``` @@ -180,12 +182,12 @@ graalpython >>> exit() ``` -More examples and additional information on Python support in GraalVM can be found in the [Python reference manual](/reference-manual/python/). +More examples and additional information on Python support in GraalVM can be found in the [Python reference manual](../../reference-manual/python/README.md). ### Ruby GraalVM Enterprise provides a high-performance Ruby runtime environment including the `gem` command that allows you to interact with RubyGems, Ruby Bundler, and much more. -The Ruby runtime is not available by default in GraalVM, but can be easily added using the [GraalVM Updater](/reference-manual/graalvm-updater/) tool: +The Ruby runtime is not available by default in GraalVM, but can be easily added using the [GraalVM Updater](../../reference-manual/graalvm-updater.md) tool: ```shell gu install ruby ``` @@ -196,7 +198,7 @@ ruby [options] program.rb ``` GraalVM Ruby runtime environment uses the -[same options as the standard implementation of Ruby](/reference-manual/ruby/Options/), +[same options as the standard implementation of Ruby](../../reference-manual/ruby/options.md), with some additions. For example: ```shell gem install chunky_png @@ -204,12 +206,12 @@ ruby -r chunky_png -e "puts ChunkyPNG::Color.to_hex(ChunkyPNG::Color('mintcream #f5fffa80 ``` -More examples and in-depth documentation can be found in the [Ruby reference manual](/reference-manual/ruby/). +More examples and in-depth documentation can be found in the [Ruby reference manual](../../reference-manual/ruby/README.md). ### R GraalVM Enterprise provides a GNU-compatible environment to run R programs directly or in the REPL mode. -Although the R language support is not available by default, you can add it to GraalVM Enterprise using the [GraalVM Updater](/reference-manual/graalvm-updater/) tool: +Although the R language support is not available by default, you can add it to GraalVM Enterprise using the [GraalVM Updater](../../reference-manual/graalvm-updater.md) tool: ```shell gu install R ``` @@ -224,12 +226,12 @@ R version 4.0.3 (FastR) [1] 2 ``` -More examples and in-depth documentation can be found in the [R reference manual](/reference-manual/r/). +More examples and in-depth documentation can be found in the [R reference manual](../../reference-manual/r/README.md). ### WebAssembly With GraalVM Enterprise you can run programs compiled to WebAssembly. -The support is not available by default, but you can add it to GraalVM using the [GraalVM Updater](/reference-manual/graalvm-updater/) tool: +The support is not available by default, but you can add it to GraalVM using the [GraalVM Updater](../../reference-manual/graalvm-updater.md) tool: ```shell gu install wasm ``` @@ -254,7 +256,8 @@ int main() { } ``` -Compile it using the most recent [Emscripten compiler frontend](https://emscripten.org/docs/tools_reference/emcc.html) version. It should produce a standalone _floyd.wasm_ file in the current working directory: +Compile it using the most recent [Emscripten compiler frontend](https://emscripten.org/docs/tools_reference/emcc.html) version. +It should produce a standalone _floyd.wasm_ file in the current working directory: ```shell emcc -o floyd.wasm floyd.c ``` @@ -264,12 +267,12 @@ Then you can run the compiled WebAssembly binary on GraalVM as follows: wasm --Builtins=wasi_snapshot_preview1 floyd.wasm ``` -More details can be found in the [WebAssembly reference manual](/reference-manual/wasm/). +More details can be found in the [WebAssembly reference manual](../../reference-manual/wasm/README.md). ## Native Images With GraalVM Enterprise you can compile Java bytecode into a platform-specific, self-contained, native executable - a native image - to achieve faster startup and a smaller footprint for your application. -The [Native Image](/reference-manual/native-image/) functionality is not available by default, but can be easily installed with the [GraalVM Updater](/reference-manual/graalvm-updater/) tool: +The [Native Image](../../reference-manual/native-image/README.md) functionality is not available by default, but can be easily installed with the [GraalVM Updater](../../reference-manual/graalvm-updater.md) tool: ```shell gu install native-image ``` @@ -284,7 +287,7 @@ public class HelloWorld { } ``` -> Note: For compilation `native-image` depends on the local toolchain. Make sure your system meets the [prerequisites](/reference-manual/native-image/#prerequisites). +> Note: For compilation `native-image` depends on the local toolchain. Make sure your system meets the [prerequisites](../../reference-manual/native-image/README.md#prerequisites). Compile _HelloWorld.java_ to bytecode and then build a native image: ```shell @@ -299,7 +302,7 @@ Invoking it executes the natively compiled code of the `HelloWorld` class as fol Hello, World! ``` -More detailed documentation on this innovative technology is available in the [Native Image reference manual](/reference-manual/native-image/). +More detailed documentation on this innovative technology is available in the [Native Image reference manual](../../reference-manual/native-image/README.md). ## Polyglot Capabilities of Native Images @@ -335,7 +338,7 @@ native-image --language:js --initialize-at-build-time PrettyPrintJSON The native image generatation will take several minutes as it does not just build the `PrettyPrintJSON` class, but also builds JavaScript. Additionally, the image building requires large amounts of physical memory, especially if you build an image with -the [Truffle language implementation framework](/graalvm-as-a-platform/language-implementation-framework/) included, which is the case here. +the [Truffle language implementation framework](../../../truffle/docs/README.md) included, which is the case here. The resulting executable can now perform JSON pretty-printing: @@ -388,24 +391,24 @@ To enable interoperability, GraalVM Enterprise provides the `--polyglot` flag. For example, running `js --jvm --polyglot example.js` executes `example.js` in a polyglot context. If the program calls any code in other supported languages, GraalVM Enterprise executes that code in the same runtime as the `example.js` application. -For more information on running polyglot applications, see [Polyglot Programming](/reference-manual/polyglot-programming/). +For more information on running polyglot applications, see [Polyglot Programming](../../reference-manual/polyglot-programming.md). ## What to Read Next ### New Users Since this guide is intended mainly for users new to GraalVM Enterprise, or users -who are familiar with GraalVM Enterprise but may have little experience using it, consider investigating more complex [Example Applications](/examples/). +who are familiar with GraalVM Enterprise but may have little experience using it, consider investigating more complex [Example Applications](../../examples/examples.md). ### Oracle Cloud Users Oracle Cloud users considering GraalVM Enterprise for their cloud workloads are -invited to read [GraalVM Enterprise on OCI](/getting-started/oci/compute-instances/). +invited to read [GraalVM Enterprise on OCI](oci/compute-instances.md). This page focuses on using GraalVM Enterprise with the Oracle Cloud Infrastructure Virtual Machine compute instance. ### Advanced Users -If you are mostly interested in GraalVM Enterprise support for a specific language, or want more in-depth details about GraalVM Enterprise's diverse features, proceed to [Reference Manuals](/reference-manual/). +If you are mostly interested in GraalVM Enterprise support for a specific language, or want more in-depth details about GraalVM Enterprise's diverse features, proceed to [Reference Manuals](../../reference-manual/reference-manuals.md). -If you are looking for the tooling support GraalVM Enterprise offers, proceed to [Debugging and Monitoring Tools](/tools/). +If you are looking for the tooling support GraalVM Enterprise offers, proceed to [Debugging and Monitoring Tools](../../tools/tools.md). -If you are considering GraalVM Enterprise as a platform for your future language or tool implementation, go to [GraalVM Enterprise as a Platform](/graalvm-as-a-platform/). +If you are considering GraalVM Enterprise as a platform for your future language or tool implementation, go to [GraalVM Enterprise as a Platform](../../../truffle/docs/README.md). You can find information on GraalVM Enterprise's security model in the [Security Guide](/security-guide/), and rich API documentation in [GraalVM SDK Javadoc](https://docs.oracle.com/en/graalvm/enterprise/21/sdk/index.html). diff --git a/docs/getting-started/graalvm-enterprise/installation-linux-aarch64.md b/docs/getting-started/graalvm-enterprise/installation-linux-aarch64.md index 320ef5e8a66d..9e21e0b69611 100644 --- a/docs/getting-started/graalvm-enterprise/installation-linux-aarch64.md +++ b/docs/getting-started/graalvm-enterprise/installation-linux-aarch64.md @@ -5,16 +5,14 @@ permalink: /getting-started/installation-linux-aarch64/ # Installation on Linux ARM64 systems -As of version 21.0, Oracle provides GraalVM Enterprise distributions based on Oracle JDK11 AArch64. +As of version 21.0, Oracle provides GraalVM Enterprise distributions based on Oracle JDK11 and Oracle JDK17 for AArch64 architecture. 
This distribution can be installed on Oracle Linux and Red Hat Enterprise Linux(RHEL) systems for AArch64 CPU architecture. -Note: The core GraalVM Enterprise distribution including all components is **experimental** on Linux ARM 64-bit systems. - You can install the GraalVM distribution for Linux ARM64 systems from an archive file (_.tar.gz_). This allows you to install GraalVM for the current user into any location, without affecting other JDK installations. 1. Navigate to [Oracle GraalVM Downloads](https://www.oracle.com/downloads/graalvm-downloads.html?selected_tab=21). -2. Select the preferable GraalVM Enterprise version in the Release Version dropdown, **11** or **16** for the Java version, **Linux** for the operating system, and **aarch64** for the architecture. +2. Select the preferable GraalVM Enterprise version in the Release Version dropdown, **11** or **17** for the Java version, **Linux** for the operating system, and **aarch64** for the architecture. 3. Click on the **GraalVM Enterprise Core** download link. Before you download a file, you must accept the [Oracle License Agreement](https://www.oracle.com/downloads/licenses/graalvm-otn-license.html) in the popup window. 4. When the download button becomes active, press it to start downloading **graalvm-ee-java11-linux-aarch64-.tar.gz**. 5. Change the directory to the location where you want to install GraalVM Enterprise, then move the _.tar.gz_ archive to it. @@ -37,6 +35,6 @@ Optionally, you can specify GraalVM Enterprise as the default JRE or JDK install ## Supported Functionalities -The 64-bit GraalVM Enterprise distribution for Linux platforms includes Oracle JDK with the GraalVM compiler enabled, the [GraalVM Updater, `gu`](/reference-manual/graalvm-updater/) tool, the JavaScript runtime, and some developer tools (e.g., Chrome inspector based debugger, Visual VM). -Support for [Native Image](/reference-manual/native-image/), Node.js, LLVM and WebAssembly runtimes can be installed with `gu`. +The 64-bit GraalVM Enterprise distribution for Linux platforms includes Oracle JDK with the GraalVM compiler enabled, the [GraalVM Updater, `gu`](../../reference-manual/graalvm-updater.md) tool, the JavaScript runtime, and some developer tools (e.g., Chrome inspector based debugger, Visual VM). +Support for [Native Image](../../reference-manual/native-image/README.md), Node.js, LLVM and WebAssembly runtimes can be installed with `gu`. Runtimes for Python, FastR, and Ruby languages are not available in this distribution yet. diff --git a/docs/getting-started/graalvm-enterprise/installation-linux.md b/docs/getting-started/graalvm-enterprise/installation-linux.md index 84c9c4e1a3a2..e40d026bc347 100644 --- a/docs/getting-started/graalvm-enterprise/installation-linux.md +++ b/docs/getting-started/graalvm-enterprise/installation-linux.md @@ -8,7 +8,7 @@ permalink: /getting-started/installation-linux/ Follow these steps to install Oracle GraalVM Enterprise Edition on the Linux operating system: 1. Navigate to [Oracle GraalVM Downloads](https://www.oracle.com/downloads/graalvm-downloads.html?selected_tab=21). -2. Select the preferable GraalVM Enterprise version in the Release Version dropdown, **8**, **11**, or **16** for the Java version, **Linux** for the operating system, and **amd64** for the architecture. +2. Select the preferable GraalVM Enterprise version in the Release Version dropdown, **8**, **11**, or **17** for the Java version, **Linux** for the operating system, and **amd64** for the architecture. 3. Click on the **GraalVM Enterprise Core** download link. Before you download a file, you must accept the [Oracle License Agreement](https://www.oracle.com/downloads/licenses/graalvm-otn-license.html) in the popup window. 4. When the download button becomes active, press it to start downloading **graalvm-ee-java-linux-amd64-.tar.gz**. 5. Change the directory to the location where you want to install GraalVM Enterprise, then move the _.tar.gz_ archive to it. @@ -35,20 +35,18 @@ The base distribution of GraalVM Enterprise for Linux (AMD64) platforms includes The base installation can be extended with: Tools/Utilities: -* [Native Image](/reference-manual/enterprise-native-image/) -- a technology to compile an application ahead-of-time into a native executable -* [LLVM toolchain](/reference-manual/llvm/) -- a set of tools and APIs for compiling native programs to bitcode that can be executed on GraalVM Enterprise -* [Java on Truffle](/reference-manual/java-on-truffle/) -- a Java Virtual Machine implementation based on a Truffle interpreter for GraalVM Enterprise +* [Native Image](../../reference-manual/native-image/README.md) -- a technology to compile an application ahead-of-time into a native executable +* [LLVM toolchain](../../reference-manual/llvm/Compiling.md#llvm-toolchain-for-compiling-cc) -- a set of tools and APIs for compiling native programs to bitcode that can be executed with on the GraalVM runtime Runtimes: -* [Node.js](/reference-manual/js/) -- Node.js 14.16.1 compatible -* [Python](/reference-manual/python/) -- Python 3.8.5 compatible -* [Ruby](/reference-manual/ruby/) -- Ruby 2.7.3 compatible -* [R](/reference-manual/r/) -- GNU R 4.0.3 compatible -* [Wasm](/reference-manual/wasm/) -- WebAssembly (Wasm) +* [Java on Truffle](../../reference-manual/java-on-truffle/README.md) -- a Java Virtual Machine implementation based on a Truffle interpreter for GraalVM +* [Node.js](../../reference-manual/js/README.md) -- Node.js v14.17.6 compatible +* [Python](../../reference-manual/python/README.md) -- Python 3.8.5 compatible +* [Ruby](../../reference-manual/ruby/README.md) -- Ruby 2.7.2 compatible +* [R](/../../reference-manual/r/README.md) -- GNU R 4.0.3 compatible +* [Wasm](../../reference-manual/wasm/README.md) -- WebAssembly (Wasm) ​ These runtimes are not part of the GraalVM Enterprise base distribution and must be installed separately. -To assist a user with installation, GraalVM Enterprise includes -**GraalVM Updater**, a command line utility to install and manage additional -functionalities. Proceed to the [installation steps](/reference-manual/graalvm-updater/#component-installation){:target="_blank"} -to add any necessary language runtime or utility from above to the GraalVM Enterprise core. +To assist a user with installation, GraalVM includes **GraalVM Updater**, a command line utility to install and manage additional functionalities. +Proceed to the [installation steps](../../reference-manual/graalvm-updater.md#component-installation) to add any necessary language runtime or utility from above to GraalVM. diff --git a/docs/getting-started/graalvm-enterprise/installation-macos.md b/docs/getting-started/graalvm-enterprise/installation-macos.md index 086dc63feb9d..6c751d28aace 100644 --- a/docs/getting-started/graalvm-enterprise/installation-macos.md +++ b/docs/getting-started/graalvm-enterprise/installation-macos.md @@ -5,19 +5,15 @@ permalink: /getting-started/installation-macos/ # Installation on macOS Platforms -GraalVM Enterprise can be installed for a single user and administrator -privileges are not required. However, if GraalVM Enterprise is meant to become a -default JDK, administrator privileges are required. +GraalVM Enterprise can be installed for a single user and administrator privileges are not required. However, if GraalVM Enterprise is meant to become a default JDK, administrator privileges are required. -GraalVM Enterprise does not provide the installation wizard, unlike Oracle JDK -distributions for macOS that come with the _.dmg_ download. Note that in macOS, -the JDK installation path is: -`/Library/Java/JavaVirtualMachines//Contents/Home`. +GraalVM Enterprise does not provide the installation wizard, unlike Oracle JDK distributions for macOS that come with the _.dmg_ download. +Note that in macOS, the JDK installation path is: `/Library/Java/JavaVirtualMachines//Contents/Home`. Follow these steps to install Oracle GraalVM Enterprise Edition on the macOS operating system: 1. Navigate to[ Oracle GraalVM Downloads](https://www.oracle.com/downloads/graalvm-downloads.html). -2. Select the preferable GraalVM Enterprise version in the Release Version dropdown, **8**, **11**, or **16** for the Java version, and **macOS** for the operating system. +2. Select the preferable GraalVM Enterprise version in the Release Version dropdown, **8**, **11**, or **17** for the Java version, and **macOS** for the operating system. 3. Click on the **GraalVM Enterprise Core** download link. Before you download a file, you must accept the [Oracle License Agreement](https://www.oracle.com/downloads/licenses/graalvm-otn-license.html) in the popup window. 4. When the download button becomes active, press it to start downloading **graalvm-ee-java-darvin-amd64-.tar.gz**. 5. Unzip the archive: @@ -66,20 +62,18 @@ The base distribution of GraalVM Enterprise for macOS platforms includes Oracle The base installation can be extended with: Tools/Utilities: -* [Native Image](/reference-manual/native-image/) -- a technology to compile an application ahead-of-time into a native executable -* [LLVM toolchain](/reference-manual/llvm/) -- a set of tools and APIs for compiling native programs to bitcode that can be executed on GraalVM Enterprise -* [Java on Truffle](/reference-manual/java-on-truffle/) -- a Java Virtual Machine implementation based on a Truffle interpreter for GraalVM Enterprise +* [Native Image](../../reference-manual/native-image/README.md) -- a technology to compile an application ahead-of-time into a native executable +* [LLVM toolchain](../../reference-manual/llvm/Compiling.md#llvm-toolchain-for-compiling-cc) -- a set of tools and APIs for compiling native programs to bitcode that can be executed with on the GraalVM runtime Runtimes: -* [Node.js](/reference-manual/js/) -- Node.js 14.16.1 compatible -* [Python](/reference-manual/python/) -- Python 3.8.5 compatible -* [Ruby](/reference-manual/ruby/) -- Ruby 2.7.3 compatible -* [R](/reference-manual/r/) -- GNU R 4.0.3 compatible -* [Wasm](/reference-manual/wasm/) -- WebAssembly (Wasm) +* [Java on Truffle](../../reference-manual/java-on-truffle/README.md) -- a Java Virtual Machine implementation based on a Truffle interpreter for GraalVM +* [Node.js](../../reference-manual/js/README.md) -- Node.js v14.17.6 compatible +* [Python](../../reference-manual/python/README.md) -- Python 3.8.5 compatible +* [Ruby](../../reference-manual/ruby/README.md) -- Ruby 2.7.2 compatible +* [R](/../../reference-manual/r/README.md) -- GNU R 4.0.3 compatible +* [Wasm](../../reference-manual/wasm/README.md) -- WebAssembly (Wasm) ​ These runtimes are not part of the GraalVM Enterprise base distribution and must be installed separately. -To assist users with installation, GraalVM Enterprise includes -**GraalVM Updater**, a command line utility to install and manage additional -functionalities. Proceed to the [installation steps](/reference-manual/graalvm-updater/#component-installation){:target="_blank"} -to add any necessary language runtime or utility from above to the GraalVM Enterprise core. +To assist a user with installation, GraalVM includes **GraalVM Updater**, a command line utility to install and manage additional functionalities. +Proceed to the [installation steps](../../reference-manual/graalvm-updater.md#component-installation) to add any necessary language runtime or utility from above to GraalVM. diff --git a/docs/getting-started/graalvm-enterprise/installation-windows.md b/docs/getting-started/graalvm-enterprise/installation-windows.md index 0807a4a50643..78d933cbe076 100644 --- a/docs/getting-started/graalvm-enterprise/installation-windows.md +++ b/docs/getting-started/graalvm-enterprise/installation-windows.md @@ -9,7 +9,7 @@ You can install Oracle GraalVM Enterprise Edition on the Windows operating syste Follow these steps: 1. Navigate to [Oracle GraalVM Downloads](https://www.oracle.com/downloads/graalvm-downloads.html). -2. Select the preferable GraalVM Enterprise version in the Release Version dropdown, **8**, **11**, or **16** for the Java version, and **Windows** for the operating system. +2. Select the preferable GraalVM Enterprise version in the Release Version dropdown, **8**, **11**, or **17** for the Java version, and **Windows** for the operating system. 3. Click on the **GraalVM Enterprise Core** download link. Before you download a file, you must accept the [Oracle License Agreement](https://www.oracle.com/downloads/licenses/graalvm-otn-license.html) in the popup window. 4. When the download button becomes active, press it to start downloading graalvm-ee-java-windows-amd64-.zip. 5. Change the directory to the location where you want to install GraalVM Enterprise, then move the _.zip_ archive to it. @@ -36,18 +36,17 @@ Optionally, you can specify GraalVM Enterprise as the JRE or JDK installation in ## Supported Functionalities -The GraalVM Enterprise distribution for Windows platforms includes Oracle JDK with the GraalVM compiler enabled, the [GraalVM Updater](/reference-manual/graalvm-updater/) tool, the JavaScript runtime, and the developer tools (e.g., Chrome inspector based debugger, Profiler, etc.). -Currently, the GraalVM Enterprise environment on Windows can be extended with [Native Image](/reference-manual/native-image/), [Java on Trufle](/reference-manual/java-on-truffle/), WebAssembly, and Node.js support. +The GraalVM Enterprise distribution for Windows platforms includes Oracle JDK with the GraalVM compiler enabled, the [GraalVM Updater](../../reference-manual/graalvm-updater.md) tool, the JavaScript runtime, and the developer tools (e.g., Chrome inspector based debugger, Profiler, etc.). +Currently, the GraalVM Enterprise environment on Windows can be extended with [Native Image](../../reference-manual/native-image/README.md), [Java on Trufle](../../reference-manual/java-on-truffle/README.md), WebAssembly, and Node.js support. ## Prerequisites for Using Native Image on Windows -To make use of Native Image on Windows, observe the following recommendations. The -required Microsoft Visual C++ (MSVC) version depends on the JDK version that -GraalVM is based on. For GraalVM Enterprise distribution based on JDK 8, you will need MSVC -2010 SP1 version. The recommended installation method is using Microsoft Windows -SDK 7.1: -1. Download the SDK file `GRMSDKX_EN_DVD.iso` for from [Microsoft](https://www.microsoft.com/en-gb/download). -2. Mount the image by opening `F:\Setup\SDKSetup.exe` directly. +On Windows, Native Image requires Visual Studio Code and Microsoft Visual C++(MSVC). +You can use Visual Studio 2017 version 15.9 or later. +There are two installation options: +- Install the Visual Studio Code Build Tools with the Windows 10 SDK +- Install Visual Studio Code with the Windows 10 SDK -For GraalVM Enterprise distribution based on JDK 11, you will need MSVC 2017 15.5.5 or later version. +The last prerequisite is the proper [Developer Command Prompt](https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=vs-2019#developer_command_prompt_shortcuts) for your version of [Visual Studio](https://visualstudio.microsoft.com/vs/). +On Windows the `native-image` tool only works when it is executed from the **x64 Native Tools Command Prompt**. -The last prerequisite, common for both distributions, is the proper [Developer Command Prompt](https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=vs-2019#developer_command_prompt_shortcuts) for your version of [Visual Studio](https://visualstudio.microsoft.com/vs/). On Windows the `native-image` tool only works when it is executed from the **x64 Native Tools Command Prompt**. +Step by step instructions on installing Visual Studio Build Tools and Windows 10 SDK, and starting using Native Image can be found [here](https://medium.com/graalvm/using-graalvm-and-native-image-on-windows-10-9954dc071311). diff --git a/docs/getting-started/graalvm-enterprise/oci/compute-instances.md b/docs/getting-started/graalvm-enterprise/oci/compute-instances.md index 341a50daaa77..221d231b9537 100644 --- a/docs/getting-started/graalvm-enterprise/oci/compute-instances.md +++ b/docs/getting-started/graalvm-enterprise/oci/compute-instances.md @@ -79,7 +79,7 @@ Now you have a ready-to-go VM instance with GraalVM Enterprise installed and rea ``` 2. Look up the necessary RPM package name and add it to GraalVM Enterprise with the `yum install command` command. -For example, to install [Native Image](/reference-manual/native-image/), which is a technology to ahead-of-time compile Java code to a standalone native executable, run this command: +For example, to install [Native Image](../../../reference-manual/native-image/README.md), which is a technology to ahead-of-time compile Java code to a standalone native executable, run this command: ```shell sudo yum install graalvm21-ee-11-native-image diff --git a/docs/graalvm-as-a-platform/graalvm-as-a-platform.md b/docs/graalvm-as-a-platform/graalvm-as-a-platform.md index 10e957fb8e01..7c5af0090264 100644 --- a/docs/graalvm-as-a-platform/graalvm-as-a-platform.md +++ b/docs/graalvm-as-a-platform/graalvm-as-a-platform.md @@ -8,21 +8,21 @@ toc_group: graalvm-as-a-platform # GraalVM as a Platform -GraalVM is an open ecosystem and allows users to implement a custom language or tool on top of it with the [Truffle language implementation framework](/graalvm-as-a-platform/language-implementation-framework/) which offers APIs for writing interpreters for programming languages in the form of Java programs. +GraalVM is an open ecosystem and allows users to implement a custom language or tool on top of it with the [Truffle language implementation framework](../../truffle/docs/README.md) which offers APIs for writing interpreters for programming languages in the form of Java programs. GraalVM loads and runs the Truffle framework, which itself is a Java program -- a collection of JAR files -- together with interpreters. These get optimized at runtime into efficient machine code for executing loaded programs. -Learn more about this framework from its [reference documentation](/graalvm-as-a-platform/language-implementation-framework/). +Learn more about this framework from its [reference documentation](../../truffle/docs/README.md). ## Implement Your Language With the [Language API](https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/package-summary.html) offered by the Truffle framework, you can implement a language interpreter on top of GraalVM. -To get started, proceed to [Implement Your Language](/graalvm-as-a-platform/implement-language/). +To get started, proceed to [Implement Your Language](implement-language.md). ## Implement Your Tool With the [Instrument API](https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/instrumentation/package-summary.html) offered by the Truffle framework, you can create language-agnostic tools like debuggers, profilers, or other instruments on top of GraalVM. -To get started, proceed to [Implement Your Tool](/graalvm-as-a-platform/implement-instrument/). +To get started, proceed to [Implement Your Tool](implement-instrument.md). diff --git a/docs/graalvm-as-a-platform/implement-instrument.md b/docs/graalvm-as-a-platform/implement-instrument.md index 1a2eb62b6290..9e67cbce0381 100644 --- a/docs/graalvm-as-a-platform/implement-instrument.md +++ b/docs/graalvm-as-a-platform/implement-instrument.md @@ -14,22 +14,18 @@ Instruments can track very fine-grained, VM-level runtime events to profile, ins ## Simple Tool -To provide an easier starting point for tool developers we have created a -[Simple Tool](https://github.com/graalvm/simpletool) example project. This is a -javadoc-rich Maven project which implements a simple code coverage tool. +To provide an easier starting point for tool developers we have created a [Simple Tool](https://github.com/graalvm/simpletool) example project. +This is a javadoc-rich Maven project which implements a simple code coverage tool. -We recommend cloning the repository and exploring the source code as a starting -point for tool development. The following sections will provide a guided tour of -the steps needed to build and run a GraalVM tool, using Simple Tool source code -as the running example. These sections do not cover all of the features of the -[Instrument API](http://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/instrumentation/package-summary.html) so we encourage you to check the javadoc for more details. +We recommend cloning the repository and exploring the source code as a starting point for tool development. +The following sections will provide a guided tour of the steps needed to build and run a GraalVM tool, using Simple Tool source code as the running example. +These sections do not cover all of the features of the [Instrument API](http://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/instrumentation/package-summary.html) so we encourage you to check the javadoc for more details. ### Requirements -As mentioned before, Simple Tool is a code coverage tool. Ultimately, it -should provide the developer with information on what percentage of source code -lines was executed, as well as exactly which lines were executed. With that in -mind, we can define some high-level requirements from our tool: +As mentioned before, Simple Tool is a code coverage tool. +Ultimately, it should provide the developer with information on what percentage of source code lines was executed, as well as exactly which lines were executed. +With that in mind, we can define some high-level requirements from our tool: 1. The tool keeps track of loaded source code. 2. The tool keeps track of executed source code. @@ -40,21 +36,17 @@ mind, we can define some high-level requirements from our tool: The main starting point for tools is subclassing the [TruffleInstrument](https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/instrumentation/TruffleInstrument.html) class. Unsurprisingly, the simple tool code base does exactly this, creating the [SimpleCoverageInstrument](https://github.com/graalvm/simpletool/blob/master/src/main/java/com/oracle/truffle/st/SimpleCoverageInstrument.java#L84) class. -The -[Registration](https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/instrumentation/TruffleInstrument.Registration.html) -annotation on the class ensures that the newly created instrument is registered -with the Instrument API, i.e., that it will be automatically -discovered by the framework. It also provides some metadata about the -instrument: ID, name, version, which services the instrument provides, and -whether the instrument is internal or not. In order for this annotation to be -effective the DSL processor needs to process this class. This is, in the case of Simple Tool, done automatically by having the DSL processor as a dependency in the [Maven configuration](https://github.com/graalvm/simpletool/blob/master/pom.xml#L83). +The [Registration](https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/instrumentation/TruffleInstrument.Registration.html) annotation on the class ensures that the newly created instrument is registered with the Instrument API, i.e., that it will be automatically discovered by the framework. +It also provides some metadata about the instrument: ID, name, version, which services the instrument provides, and whether the instrument is internal or not. +In order for this annotation to be effective the DSL processor needs to process this class. +This is, in the case of Simple Tool, done automatically by having the DSL processor as a dependency in the [Maven configuration](https://github.com/graalvm/simpletool/blob/master/pom.xml#L83). Now we will look back at the implementation of the `SimpleCoverageInstrument` class, namely which methods from `TruffleInstrument` it overrides. These are [onCreate](https://github.com/graalvm/simpletool/blob/master/src/main/java/com/oracle/truffle/st/SimpleCoverageInstrument.java#L130), [onDispose](https://github.com/graalvm/simpletool/blob/master/src/main/java/com/oracle/truffle/st/SimpleCoverageInstrument.java#L182), and [getOptionDescriptors](https://github.com/graalvm/simpletool/blob/master/src/main/java/com/oracle/truffle/st/SimpleCoverageInstrument.java#L245). The `onCreate` and `onDispose` methods are self-explanatory: they are called by the framework when the instrument is created and disposed. We will discuss their implementations later, but first let us discuss the remaining one: `getOptionDescriptors`. -The [Truffle language implementation framework](/graalvm-as-a-platform/language-implementation-framework/) comes with its own system for specifying command-line options. +The [Truffle language implementation framework](../../truffle/docs/README.md) comes with its own system for specifying command-line options. These options allow tool users to control the tool either from the command line or when creating [polyglot contexts](https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/Context.html). It is annotation-based, and examples for such options are the [ENABLED](https://github.com/graalvm/simpletool/blob/master/src/main/java/com/oracle/truffle/st/SimpleCoverageInstrument.java#L91) and [PRINT_COVERAGE](https://github.com/graalvm/simpletool/blob/master/src/main/java/com/oracle/truffle/st/SimpleCoverageInstrument.java#L97) fields of `SimpleCoverageInstrument`. Both of these are static final fields of the type [OptionKey](https://www.graalvm.org/truffle/javadoc/org/graalvm/options/OptionKey.html) annotated with [Option](https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/Option.html) which, similar to the `Registration` annotation, provides some metadata for the option. @@ -68,6 +60,7 @@ Similarly, in the `onDispose` method we check the options for the state of the ` What does it mean "to enable a tool?" In general, it means that we tell the framework about the events we are interested in and how we want to react to them. Looking at our `enable` method, it does the following: + - First, it defines [SourceSectionFilter](https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/instrumentation/SourceSectionFilter.html). This filter is a declarative definition of the parts of the source code we are interested in. In our example, we care about all nodes that are considered expressions, and we do not care about internal language parts. @@ -89,22 +82,14 @@ The instrument keeps a mapping from each `Source` to a [Coverage](https://github ### Execution Event Node Guest languages are implemented as Abstract Syntax Tree (AST) interpreters. -The language implementers annotate certain nodes with tags, which allows us to -select which nodes we are interested in, by using the aforementioned -`SourceSectionFilter`, in a language-agnostic manner. - -The main power of the Instrument API lies in its ability to insert specialised -nodes in the AST which "wrap" the nodes of interest. These nodes are built using -the same infrastructure that the language developers use, and are, from the -perspective of the runtime, indistinguishable from the language nodes. This -means that all of the techniques used to optimize guest languages into such high -performing language implementations are available to the tool developers as -well. +The language implementers annotate certain nodes with tags, which allows us to select which nodes we are interested in, by using the aforementioned `SourceSectionFilter`, in a language-agnostic manner. + +The main power of the Instrument API lies in its ability to insert specialised nodes in the AST which "wrap" the nodes of interest. +These nodes are built using the same infrastructure that the language developers use, and are, from the perspective of the runtime, indistinguishable from the language nodes. +This means that all of the techniques used to optimize guest languages into such high performing language implementations are available to the tool developers as well. More information about these techniques is available in the [language implementation documentation](https://github.com/oracle/graal/tree/master/truffle/docs). -Suffice it to say that for Simple Tool to meet its second requirement, we need to -instrument all expressions with our own node that will notify us when that -expression is executed. +Suffice it to say that for Simple Tool to meet its second requirement, we need to instrument all expressions with our own node that will notify us when that expression is executed. For this task we use the [CoverageNode](https://github.com/graalvm/simpletool/blob/master/src/main/java/com/oracle/truffle/st/CoverageNode.java). It is a subclass of [ExecutionEventNode](https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/instrumentation/ExecutionEventNode.html) which, as the name implies, is used to instrument events during execution. @@ -113,16 +98,13 @@ This method is invoked when the "wrapped" node returns a value, i.e., is success The implementation is rather simple. We just notify the instrument that the node with this particular `SourceSection` has been executed, and the instrument updates the `Coverage` object in its coverage map. The instrument is notified only once per node, as the logic is guarded by the [flag](https://github.com/graalvm/simpletool/blob/master/src/main/java/com/oracle/truffle/st/CoverageNode.java#L60). -The fact that this flag is annotated with [CompilationFinal](https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/CompilerDirectives.CompilationFinal.html) and that the call to the instrument is preceded by a call to [transferToInterpreterAndInvalidate()](https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/CompilerDirectives.html#transferToInterpreterAndInvalidate--) is a standard technique in Truffle which ensures that once this instrumentation is no longer needed (i.e., a node has been executed), the instrumentation is removed from further compilations, along with any performance overhead. +The fact that this flag is annotated with [CompilationFinal](https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/CompilerDirectives.CompilationFinal.html) and that the call to the instrument is preceded by a call to [transferToInterpreterAndInvalidate()](https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/CompilerDirectives.html#transferToInterpreterAndInvalidate--) is a standard technique in Truffle, which ensures that once this instrumentation is no longer needed (i.e., a node has been executed), the instrumentation is removed from further compilations, along with any performance overhead. -In order for the framework to know how to instantiate the `CoverageNode` when it -is needed, we need to provide a factory for it. +In order for the framework to know how to instantiate the `CoverageNode` when it is needed, we need to provide a factory for it. The factory is the [CoverageEventFactory](https://github.com/graalvm/simpletool/blob/master/src/main/java/com/oracle/truffle/st/CoverageEventFactory.java), a subclass of [ExecutionEventNodeFactory](https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/instrumentation/ExecutionEventNodeFactory.html). This class just ensures that each `CoverageNode` knows the `SourceSection` it is instrumenting by looking it up in the provided [EventContext](https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/instrumentation/EventContext.html). -Finally, when we are [enabling the instrument](https://github.com/graalvm/simpletool/blob/master/src/main/java/com/oracle/truffle/st/SimpleCoverageInstrument.java#L173), -we tell the instrumenter to use our factory to "wrap" the nodes selected by our -filter. +Finally, when we are [enabling the instrument](https://github.com/graalvm/simpletool/blob/master/src/main/java/com/oracle/truffle/st/SimpleCoverageInstrument.java#L173), we tell the instrumenter to use our factory to "wrap" the nodes selected by our filter. ### Interaction Between Users and Instruments @@ -146,7 +128,7 @@ As mentioned before, Simple Tool is a Maven project. Setting `JAVA_HOME` to a GraalVM installation and running `mvn package` produces a `target/simpletool-.jar`. This is the Simple Tool distribution form. -The [Truffle framework](/graalvm-as-a-platform/language-implementation-framework/) offers a clear separation between the language/tooling code and the application code. +The [Truffle framework](../../truffle/docs/README.md) offers a clear separation between the language/tooling code and the application code. For this reason, putting the JAR on the class path will not result in the framework realizing a new tool is needed. To achieve this we use `--vm.Dtruffle.class.path.append=/path/to/simpletool-.jar` as is illustrated in a [launcher script for our simple tool](https://github.com/graalvm/simpletool/blob/master/simpletool). This script also shows we can [set the CLI options](https://github.com/graalvm/simpletool/blob/master/simpletool#L19) we specified for Simple Tool. @@ -237,14 +219,18 @@ The following examples are intended to show common use-cases that can be solved ### Instrumentation Event Listeners -The Instrument API is defined in the `com.oracle.truffle.api.instrumentation` package. Instrumentation agents can be developed by extending the `TruffleInstrument` class, and can be attached to a running GraalVM instance using the `Instrumenter` class. Once attached to a running language runtime, instrumentation agents remain usable as long as the language runtime is not disposed. Instrumentation agents on GraalVM can monitor a variety of VM-level runtime events, including any of the following: +The Instrument API is defined in the `com.oracle.truffle.api.instrumentation` package. +Instrumentation agents can be developed by extending the `TruffleInstrument` class, and can be attached to a running GraalVM instance using the `Instrumenter` class. +Once attached to a running language runtime, instrumentation agents remain usable as long as the language runtime is not disposed. +Instrumentation agents on GraalVM can monitor a variety of VM-level runtime events, including any of the following: 1. _Source code-related events_: The agent can be notified every time a new [Source](http://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/source/Source.html) or [SourceSection](http://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/source/SourceSection.html) element is loaded by the monitored language runtime. 2. _Allocation events_: The agent can be notified every time a new object is allocated in the memory space of the monitored language runtime. 3. _Language runtime and thread creation events_: The agent can be notified as soon as a new [execution context](http://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.html) or a new thread for a monitored language runtime is created. 4. _Application execution events_: The agent gets notified every time a monitored application executes a specific set of language operations. Examples of such operations include language statements and expressions, thus allowing an instrumentation agent to inspect running applications with very high precision. -For each execution event, instrumentation agents can define _filtering_ criteria that will be used by the GraalVM instrumentation runtime to monitor only the relevant execution events. Currently, GraalVM instruments accept one of the following two filter types: +For each execution event, instrumentation agents can define _filtering_ criteria that will be used by the GraalVM instrumentation runtime to monitor only the relevant execution events. +Currently, GraalVM instruments accept one of the following two filter types: 1. `AllocationEventFilter` to filter allocation events by allocation type. 2. `SourceSectionFilter` to filter source code locations in an application. @@ -258,9 +244,12 @@ SourceSectionFilter.newBuilder() .build() ``` -The filter in the example can be used to monitor the execution of all JavaScript statements in a given application. Other filtering options such as line numbers or file extensions can also be provided. +The filter in the example can be used to monitor the execution of all JavaScript statements in a given application. +Other filtering options such as line numbers or file extensions can also be provided. -Source section filters like the one in the example can use _Tags_ to specify a set of execution events to be monitored. Language-agnostic tags such as statements and expressions are defined in the [`com.oracle.truffle.api.instrumentation.Tag`](http://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/instrumentation/Tag.html) class, and are supported by all GraalVM languages. In addition to standard tags, GraalVM languages may provide other, language-specific, tags to enable fine-grained profiling of language-specific events. (As an example, the GraalVM JavaScript engine provides JavaScript-specific tags to track the usages of ECMA builtin objects such as `Array`, `Map`, or `Math`.) +Source section filters like the one in the example can use _Tags_ to specify a set of execution events to be monitored. Language-agnostic tags such as statements and expressions are defined in the [`com.oracle.truffle.api.instrumentation.Tag`](http://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/instrumentation/Tag.html) class, and are supported by all GraalVM languages. +In addition to standard tags, GraalVM languages may provide other, language-specific, tags to enable fine-grained profiling of language-specific events. +(As an example, the GraalVM JavaScript engine provides JavaScript-specific tags to track the usages of ECMA builtin objects such as `Array`, `Map`, or `Math`.) ### Monitoring Execution Events @@ -271,7 +260,8 @@ Application execution events enable very precise and detailed monitoring. GraalV ### Simple Instrumentation Agent -A simple example of a custom instrumentation agent used to perform runtime code coverage can be found in the `CoverageExample` class. What follows is an overview of the agent, its design, and its capabilities. +A simple example of a custom instrumentation agent used to perform runtime code coverage can be found in the `CoverageExample` class. +What follows is an overview of the agent, its design, and its capabilities. All instruments extend the `TruffleInstrument` abstract class and are registered in the GraalVM runtime through the `@Registration` annotation: @@ -287,7 +277,9 @@ public final class CoverageExample extends TruffleInstrument { } ``` -Instruments override the `onCreate(Env env)` method to perform custom operations at instrument loading time. Typically, an instrument would use this method to register itself in the existing GraalVM execution environment. As an example, an instrument using AST nodes can be registered in the following way: +Instruments override the `onCreate(Env env)` method to perform custom operations at instrument loading time. +Typically, an instrument would use this method to register itself in the existing GraalVM execution environment. +As an example, an instrument using AST nodes can be registered in the following way: ```java @Override @@ -325,7 +317,10 @@ Execution event nodes can implement certain callback methods to intercept runtim 2. `onReturnValue`: executed after a source code element returns a value. 3. `onReturnExceptional`: executed in case the filtered source code element throws an exception. -Execution event nodes are created on a _per code location_ basis. Therefore, they can be used to store data specific to a given source code location in the instrumented application. As an example, an instrumentation node can simply keep track of all code locations that have already been visited using a node-local flag. Such a node-local `boolean` flag can be used to track the execution of AST nodes in the following way: +Execution event nodes are created on a _per code location_ basis. +Therefore, they can be used to store data specific to a given source code location in the instrumented application. +As an example, an instrumentation node can simply keep track of all code locations that have already been visited using a node-local flag. +Such a node-local `boolean` flag can be used to track the execution of AST nodes in the following way: ```java // To keep track of all source code locations executed @@ -349,10 +344,13 @@ public ExecutionEventNode create(final EventContext ec) { } ``` -As the above code shows, an `ExecutionEventNode` is a valid AST node. This implies that the instrumentation code will be optimized by the GraalVM runtime together with the instrumented application, resulting in minimal instrumentation overhead. Furthermore, this allows instrument developers to use the [Truffle framework compiler directives](http://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/CompilerDirectives.html) directly from instrumentation nodes. In the example, compiler directives are used to inform the GraalVM compiler that `visited` can be considered compilation-final. +As the above code shows, an `ExecutionEventNode` is a valid AST node. +This implies that the instrumentation code will be optimized by the GraalVM runtime together with the instrumented application, resulting in minimal instrumentation overhead. Furthermore, this allows instrument developers to use the [Truffle framework compiler directives](http://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/CompilerDirectives.html) directly from instrumentation nodes. +In the example, compiler directives are used to inform the GraalVM compiler that `visited` can be considered compilation-final. -Each instrumentation node is bound to a specific code location. Such locations can be accessed by the agent using the provided [`EventContext`](http://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/instrumentation/EventContext.html) object. -The context object gives instrumentation nodes access to a variety of information about the current AST nodes being executed. Examples of query APIs available to instrumentation agents through `EventContext` include: +Each instrumentation node is bound to a specific code location. +Such locations can be accessed by the agent using the provided [`EventContext`](http://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/instrumentation/EventContext.html) object. The context object gives instrumentation nodes access to a variety of information about the current AST nodes being executed. +Examples of query APIs available to instrumentation agents through `EventContext` include: 1. `hasTag`: to query an instrumented node for a certain node `Tag` (e.g., to check if a statement node is also a conditional node). 2. `getInstrumentedSourceSection`: to access the [`SourceSection`](http://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/source/SourceSection.html) associated with the current node. @@ -376,7 +374,10 @@ SourceSectionFilter inputGeneratingLocations = SourceSectionFilter.newBuilder() instrumenter.attachExecutionEventFactory(sourceSectionFilter, inputGeneratingLocations, factory); ``` -The first source section filter (`sourceSectionFilter`, in the example) is a normal filter equivalent to other filters described before, and is used to identify the source code locations to be monitored. The second section filter, `inputGeneratingLocations`, is used by the agent to specify the _intermediate values_ that should be monitored for a certain source section. Intermediate values correspond to _all_ observable values that are involved in the execution of a monitored code element, and are reported to the instrumentation agent by means of the `onInputValue` callback. As an example, let us assume an agent needs to profile all _operand_ values provided to sum operations (i.e., `+`) in JavaScript: +The first source section filter (`sourceSectionFilter`, in the example) is a normal filter equivalent to other filters described before, and is used to identify the source code locations to be monitored. +The second section filter, `inputGeneratingLocations`, is used by the agent to specify the _intermediate values_ that should be monitored for a certain source section. +Intermediate values correspond to _all_ observable values that are involved in the execution of a monitored code element, and are reported to the instrumentation agent by means of the `onInputValue` callback. +As an example, let us assume an agent needs to profile all _operand_ values provided to sum operations (i.e., `+`) in JavaScript: ```javascript var a = 3; @@ -421,13 +422,19 @@ onEnter - VariableWrite onReturnValue - VariableWrite ``` -The `onInputValue` method can be used in combination with source section filters to intercept very fine-grained execution events such as intermediate values used by language expressions. The intermediate values that are accessible to the Instrumentation framework greatly depend on the instrumentation support provided by each language. Moreover, languages may provide additional metadata associated with language-specific `Tag` classes. +The `onInputValue` method can be used in combination with source section filters to intercept very fine-grained execution events such as intermediate values used by language expressions. +The intermediate values that are accessible to the Instrumentation framework greatly depend on the instrumentation support provided by each language. +Moreover, languages may provide additional metadata associated with language-specific `Tag` classes. ### Altering the Execution Flow of an Application -The instrumentation capabilities that we have presented so far enable users to _observe_ certain aspects of a running application. In addition to passive monitoring of an application's behavior, the Instrument API features support for actively _altering_ the behavior of an application at runtime. Such capabilities can be used to write complex instrumentation agents that affect the behavior of a running application to achieve specific runtime semantics. For example, one could alter the semantics of a running application to ensure that certain methods or functions are never executed (e.g., by throwing an exception when they are called). +The instrumentation capabilities that we have presented so far enable users to _observe_ certain aspects of a running application. +In addition to passive monitoring of an application's behavior, the Instrument API features support for actively _altering_ the behavior of an application at runtime. +Such capabilities can be used to write complex instrumentation agents that affect the behavior of a running application to achieve specific runtime semantics. +For example, one could alter the semantics of a running application to ensure that certain methods or functions are never executed (e.g., by throwing an exception when they are called). -Instrumentation agents with such capabilities can be implemented by leveraging the `onUnwind` callback in execution event listeners and factories. As an example, let's consider the following JavaScript code: +Instrumentation agents with such capabilities can be implemented by leveraging the `onUnwind` callback in execution event listeners and factories. +As an example, let's consider the following JavaScript code: ```javascript function inc(x) { @@ -484,6 +491,10 @@ public static class UniversalAnswerInstrument extends TruffleInstrument { } ``` -When enabled, the instrument will execute its `onReturnValue` callback each time a function call returns. The callback reads the associated source section (using `getInstrumentedSourceSection`) and looks for a specific source code pattern (the function call `inc(c)`, in this case). As soon as such code pattern is found, the instrument throws a special runtime exception, called `UnwindException`, that instructs the Instrumentation framework about a change in the current application's execution flow. The exception is intercepted by the `onUnwind` callback of the instrumentation agent, which can be used to return _any_ arbitrary value to the original instrumented application. +When enabled, the instrument will execute its `onReturnValue` callback each time a function call returns. +The callback reads the associated source section (using `getInstrumentedSourceSection`) and looks for a specific source code pattern (the function call `inc(c)`, in this case). +As soon as such code pattern is found, the instrument throws a special runtime exception, called `UnwindException`, that instructs the Instrumentation framework about a change in the current application's execution flow. +The exception is intercepted by the `onUnwind` callback of the instrumentation agent, which can be used to return _any_ arbitrary value to the original instrumented application. -In the example, all calls to `inc(c)` will return `42` regardless of any application-specific data. A more realistic instrument might access and monitor several aspects of an application, and might not rely on source code locations, but rather on object instances or other application-specific data. +In the example, all calls to `inc(c)` will return `42` regardless of any application-specific data. +A more realistic instrument might access and monitor several aspects of an application, and might not rely on source code locations, but rather on object instances or other application-specific data. diff --git a/docs/graalvm-as-a-platform/implement-language.md b/docs/graalvm-as-a-platform/implement-language.md index 28c182776fc9..15babb18e14c 100644 --- a/docs/graalvm-as-a-platform/implement-language.md +++ b/docs/graalvm-as-a-platform/implement-language.md @@ -11,7 +11,7 @@ toc_group: graalvm-as-a-platform We have found that the easiest way to get started with implementing your own language is by extending an existing language such as SimpleLanguage. [SimpleLanguage](https://github.com/graalvm/simplelanguage) is a demonstration language built using the [Language API](https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/package-summary.html). The SimpleLanguage project provides a showcase on how to use the Language APIs for writing your own language. -It aims to use most of the available [Truffle language implementation framework](/graalvm-as-a-platform/language-implementation-framework/) (henceforth "Truffle") features, and documents their use extensively with inline source documentation. +It aims to use most of the available [Truffle language implementation framework](../../truffle/docs/README.md) (henceforth "Truffle") features, and documents their use extensively with inline source documentation. To start, ensure [Maven3](https://maven.apache.org/download.cgi) and GraalVM are available in your system. @@ -29,12 +29,7 @@ For macOS, use: export JAVA_HOME=/path/to/graalvm/Contents/Home export PATH=/path/to/graalvm/Contents/Home/bin:$PATH ``` -4. Execute `mvn package` from the SimpleLanguage folder to build the language. -The command also builds a `slnative` executable in the `simplelanguage/native` -directory and a `sl-component.jar` language component which later can be installed -into GraalVM using the [GraalVM Updater](../reference-manual/graalvm-updater.md) tool. -Please verify ithat the `native-image` plugin is available in your GraalVM distribution -to avoid build failure: +4. Execute `mvn package` from the SimpleLanguage folder to build the language. The command also builds a `slnative` executable in the `simplelanguage/native` directory and a `sl-component.jar` language component which later can be installed into GraalVM using the [GraalVM Updater](../reference-manual/graalvm-updater.md) tool. Please verify ithat the `native-image` plugin is available in your GraalVM distribution to avoid build failure: ```shell gu list gu install native-image @@ -53,7 +48,8 @@ The SimpleLanguage demonstration language is licensed under the [Universal Permi ## IDE Setup -The [Truffle framework](/graalvm-as-a-platform/language-implementation-framework/) provides language-agnostic infrastructure to realize standard IDE features by providing additional APIs. If you would like to experiment with your language and get the benefits of an IDE, consider importing SimpleLanguage as an example. +The [Truffle framework](../../truffle/docs/README.md) provides language-agnostic infrastructure to realize standard IDE features by providing additional APIs. +If you would like to experiment with your language and get the benefits of an IDE, consider importing SimpleLanguage as an example. ### Eclipse @@ -109,21 +105,17 @@ Then attach a Java remote debugger (like Eclipse) on port 8000. Languages implemented with the [Truffle framework](https://github.com/oracle/graal/tree/master/truffle) can be packaged as _components_ which later can be installed into GraalVM using the [GraalVM Updater](../reference-manual/graalvm-updater.md) tool. Running `mvn package` in the SimpleLanguage folder also builds a `sl-component.jar`. -This file is the SimpleLanguage component for GraalVM and can be installed by -running: +This file is the SimpleLanguage component for GraalVM and can be installed by running: ```shell gu -L install /path/to/sl-component.jar ``` ## SimpleLanguage Native Image -A language built with Truffle can be AOT compiled using [Native Image](../reference-manual/native-image/README.md). Running -`mvn package` in the SimpleLanguage folder also builds a `slnative` executable -in the `native` directory. This executable is the full SimpleLanguage -implementation as a single native application, and has no need for GraalVM in -order to execute SimpleLanguage code. Besides this, a big advantage of using the -native executable when compared to running on GraalVM is the greatly faster -startup time as shown bellow: +A language built with Truffle can be AOT compiled using [Native Image](../reference-manual/native-image/README.md). +Running `mvn package` in the SimpleLanguage folder also builds a `slnative` executable in the `native` directory. +This executable is the full SimpleLanguage implementation as a single native application, and has no need for GraalVM in order to execute SimpleLanguage code. +Besides this, a big advantage of using the native executable when compared to running on GraalVM is the greatly faster startup time as shown bellow: ```shell time ./sl language/tests/HelloWorld.sl == running on org.graalvm.polyglot.Engine@2db0f6b2 @@ -143,23 +135,17 @@ user 0m0.000s sys 0m0.000s ``` -This snipped shows a timed execution of a "Hello World" program using the `sl` -launcher script, which runs SimpleLanguage on GraalVM, using Native -Image. We can see that when running on GraalVM the execution takes 405ms. Since -our SimpleLanguage program does just one print statement, we can conclude that -almost all of this time is spent starting up GraalVM and initializing the -language itself. When using the native executable we see that the execution takes -only 4ms, showing two orders of magnitude faster startup than running on -GraalVM. +This snipped shows a timed execution of a "Hello World" program using the `sl` launcher script, which runs SimpleLanguage on GraalVM, using Native Image. +We can see that when running on GraalVM the execution takes 405ms. +Since our SimpleLanguage program does just one print statement, we can conclude that almost all of this time is spent starting up GraalVM and initializing the language itself. +When using the native executable we see that the execution takes only 4ms, showing two orders of magnitude faster startup than running on GraalVM. For more information on the `native-image` tool consider reading the [reference manual](../reference-manual/native-image/README.md). ### Disable SimpleLanguage Native Image Build -Building the native executable through Maven is attached to the Maven `package` -phase. Since the native executable build can take a bit of time, we provide the -option to skip this build by setting the `SL_BUILD_NATIVE` environment variable -to `false` like so: +Building the native executable through Maven is attached to the Maven `package` phase. +Since the native executable build can take a bit of time, we provide the option to skip this build by setting the `SL_BUILD_NATIVE` environment variable to `false` like so: ```shell export SL_BUILD_NATIVE=false @@ -178,12 +164,11 @@ Skipping the native image build because SL_BUILD_NATIVE is set to false. ... ``` -## Run SimpleLanguage with the Newest Compiler 21.2.0 +## Run SimpleLanguage with the Newest Compiler 21.3.0 -In the outstanding case that you need to execute SimpleLanguage with the newest -version of the GraalVM compiler, please follow these instructions: +In the outstanding case that you need to execute SimpleLanguage with the newest version of the GraalVM compiler, please follow these instructions: -1. Download the latest [JVMCI JDK 8](https://github.com/graalvm/graal-jvmci-8/releases/) and point JAVA_HOME at it: +1. Download the latest [JVMCI JDK 8](https://github.com/graalvm/graal-jvmci-8/releases/) and point `JAVA_HOME` at it: ```shell export JAVA_HOME=/path/to/openjdk-8u292-jvmci-21.1-b04 ``` @@ -210,61 +195,52 @@ mx build ``` 7. Run SimpleLanguage using the mx command: ```shell -mx -v --jdk=jvmci vm -cp /path/to/simplelanguage/launcher/target/launcher-21.2.0-SNAPSHOT.jar:/path/to/simplelanguage/language/target/simplelanguage.jar com.oracle.truffle.sl.launcher.SLMain /path/to/simplelanguage/language/tests/SlScript.sl +mx -v --jdk=jvmci vm -cp /path/to/simplelanguage/launcher/target/launcher-21.3.0-SNAPSHOT.jar:/path/to/simplelanguage/language/target/simplelanguage.jar com.oracle.truffle.sl.launcher.SLMain /path/to/simplelanguage/language/tests/SlScript.sl ``` ## Run SimpleLanguage Using Command Line -Executing SimpleLanguage code is normally done with the `sl` script which sets -up the necessary command line depending on whether `JAVA_HOME` points to -GraalVM or another JVM installation. The following subsections describe the -command line for both cases. +Executing SimpleLanguage code is normally done with the `sl` script which sets up the necessary command line depending on whether `JAVA_HOME` points to GraalVM or another JVM installation. +The following subsections describe the command line for both cases. ### Run SimpleLanguage with GraalVM as JAVA_HOME -Assuming `JAVA_HOME` points to the GraalVM installation and that the current -working directory is the `simplelanguage` directory, to run SimpleLanguage one -should execute the following command: +Assuming `JAVA_HOME` points to the GraalVM installation and that the current working directory is the `simplelanguage` directory, to run SimpleLanguage one should execute the following command: ```shell $JAVA_HOME/bin/java \ - -cp launcher/target/launcher-21.2.0-SNAPSHOT.jar \ + -cp launcher/target/launcher-21.3.0-SNAPSHOT.jar \ -Dtruffle.class.path.append=language/target/simplelanguage.jar \ com.oracle.truffle.sl.launcher.SLMain language/tests/Add.sl ``` -In short, we place the launcher JAR on the class path and execute its main -class, but we inform GraalVM of the presence of SimpleLanguage by using the -`-Dtruffle.class.path.append` option and providing it the path to the fat -language JAR. Having the language on a separate class path ensures a strong -separation between the language implementation and its embedding context (in -this case, the launcher). +In short, we place the launcher JAR on the class path and execute its main class, but we inform GraalVM of the presence of SimpleLanguage by using the `-Dtruffle.class.path.append` option and providing it the path to the fat language JAR. +Having the language on a separate class path ensures a strong separation between the language implementation and its embedding context (in this case, the launcher). #### Disable Class Path Separation *NOTE! This should only be used during development.* -For development purposes it is useful to disable the class path separation and enable having the -language implementation on the application class path (for example, for testing +For development purposes it is useful to disable the class path separation and enable having the language implementation on the application class path (for example, for testing the internals of the language). -For the GraalVM distribution based on JDK 8, you can add the `-XX:-UseJVMCIClassLoader` -option. This disables the class path isolation, enabling the language -implementation to be placed on the application class path. The command line can -be as follows: +For the GraalVM distribution based on JDK 8, you can add the `-XX:-UseJVMCIClassLoader` option. +This disables the class path isolation, enabling the language implementation to be placed on the application class path. +The command line can be as follows: ```shell $JAVA_HOME/bin/java \ -XX:-UseJVMCIClassLoader -Dgraalvm.locatorDisabled=true \ - -cp launcher/target/launcher-21.2.0-SNAPSHOT.jar:language/target/simplelanguage.jar \ + -cp launcher/target/launcher-21.3.0-SNAPSHOT.jar:language/target/simplelanguage.jar \ com.oracle.truffle.sl.launcher.SLMain language/tests/Add.sl ``` -For the JDK 11-based distribution of GraalVM, the `-XX:-UseJVMCIClassLoader` option -is not valid. The Java Module System isolation is used. You can achieve the same behavior -using `--add-exports` or `--upgrade-module-path`. The latter is preferable. +For the JDK 11-based distribution of GraalVM, the `-XX:-UseJVMCIClassLoader` option is not valid. +The Java Module System isolation is used. You can achieve the same behavior using `--add-exports` or `--upgrade-module-path`. +The latter is preferable. -The Language API JAR on Maven Central exports all API packages in its module-info. Apply the `--upgrade-module-path` option together with `-Dgraalvm.locatorDisabled=true` and this JAR to export Language API packages: +The Language API JAR on Maven Central exports all API packages in its module-info. +Apply the `--upgrade-module-path` option together with `-Dgraalvm.locatorDisabled=true` and this JAR to export Language API packages: ```shell -Dgraalvm.locatorDisabled=true --module-path=:${truffle.dir} --upgrade-module-path=${truffle.dir}/truffle-api.jar ``` @@ -273,18 +249,13 @@ A sample POM using `--upgrade-module-path` to export Language API packages can b ### Other JVM Implementations -Unlike GraalVM, which includes all the dependencies needed to run a language -implemented with [Truffle](/graalvm-as-a-platform/language-implementation-framework/), other JVM implementations need additional -JARs to be present on the class path. These are the Language API and GraalVM SDK -JARs available from Maven Central. +Unlike GraalVM, which includes all the dependencies needed to run a language implemented with [Truffle](../../truffle/docs/README.md), other JVM implementations need additional JARs to be present on the class path. +These are the Language API and GraalVM SDK JARs available from Maven Central. -Assuming `JAVA_HOME` points to a stock JDK installation, and that the current -working directory is the `simplelanguage` directory and the Language API and -GraalVM SDK JARs are present in that directory, one can execute SimpleLanguage -with the following command: +Assuming `JAVA_HOME` points to a stock JDK installation, and that the current working directory is the `simplelanguage` directory and the Language API and GraalVM SDK JARs are present in that directory, one can execute SimpleLanguage with the following command: ```shell $JAVA_HOME/bin/java \ - -cp graal-sdk-21.2.0.jar:truffle-api-21.2.0.jar:launcher/target/launcher-21.2.0-SNAPSHOT.jar:language/target/simplelanguage.jar \ + -cp graal-sdk-21.3.0.jar:truffle-api-21.3.0.jar:launcher/target/launcher-21.3.0-SNAPSHOT.jar:language/target/simplelanguage.jar \ com.oracle.truffle.sl.launcher.SLMain language/tests/Add.sl ``` diff --git a/docs/guides/guides.md b/docs/guides/guides.md index cddfe00d279a..ee499535af58 100644 --- a/docs/guides/guides.md +++ b/docs/guides/guides.md @@ -21,10 +21,10 @@ At runtime, an application is loaded and executed normally by the JVM. In order to follow the steps in this guide, you must have GraalVM installed. In case you do not have it installed, getting GraalVM downloaded and ready-to-go should only take a few minutes. Choose your operating system and proceed to the installation steps: -- [Linux](/docs/getting-started/linux/) -- [Linux AArch64](/docs/getting-started/linux-aarch64/) -- [macOS](/docs/getting-started/macos/) -- [Windows](/docs/getting-started/windows/) +- [Linux](../getting-started/graalvm-community/linux.md) +- [Linux AArch64](../getting-started/graalvm-community/linux-aarch64.md) +- [macOS](../getting-started/graalvm-community/macos.md) +- [Windows](../getting-started/graalvm-community/windows.md) For the purpose of this guide, GraalVM Enterprise based on Java 11 distribution for macOS platform is used. To ensure you have successfully installed GraalVM, verify it is available in the `PATH` environment variable and the `JAVA_HOME` points to it. diff --git a/docs/introduction.md b/docs/introduction.md index 65ddeb55c202..b8af73d11e14 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -26,7 +26,7 @@ This page provides an architectural overview of GraalVM and its runtime modes, s GraalVM adds an [advanced just-in-time (JIT) optimizing compiler](https://github.com/oracle/graal/tree/master/compiler), which is written in Java, to the HotSpot Java Virtual Machine. -In addition to running Java and JVM-based languages, GraalVM's [Truffle language implementation framework](/graalvm-as-a-platform/language-implementation-framework/) makes it possible to run JavaScript, Ruby, Python, and a number of other popular languages on the JVM. +In addition to running Java and JVM-based languages, [GraalVM's language implementation framework (Truffle)](../truffle/docs/README.md) makes it possible to run JavaScript, Ruby, Python, and a number of other popular languages on the JVM. With GraalVM Truffle, Java and other supported languages can directly interoperate with each other and pass data back and forth in the same memory space. ## Runtime Modes @@ -34,18 +34,18 @@ With GraalVM Truffle, Java and other supported languages can directly interopera GraalVM is unique as a runtime environment offering several modes of operation: JVM runtime mode, Native Image, Java on Truffle (the same Java applications can be run on either). #### JVM Runtime Mode -When running programs on the HotSpot JVM, GraalVM defaults to the [GraalVM compiler](/reference-manual/compiler/) as the top-tier JIT compiler. +When running programs on the HotSpot JVM, GraalVM defaults to the [GraalVM compiler](reference-manual/compiler.md) as the top-tier JIT compiler. At runtime, an application is loaded and executed normally on the JVM. The JVM passes bytecodes for Java or any other JVM-native language to the compiler, which compiles that to the machine code and returns it to the JVM. -Interpreters for supported languages, written on top of the [Truffle framework](/graalvm-as-a-platform/language-implementation-framework/), are themselves Java programs that run on the JVM. +Interpreters for supported languages, written on top of the [Truffle framework](../truffle/docs/README.md), are themselves Java programs that run on the JVM. #### Native Image -[Native Image](/reference-manual/native-image/) is an innovative technology that compiles Java code into a standalone binary executable or a native shared library. +[Native Image](reference-manual/native-image/README.md) is an innovative technology that compiles Java code into a standalone binary executable or a native shared library. The Java bytecode that is processed during the native image build includes all application classes, dependencies, third party dependent libraries, and any JDK classes that are required. A generated self-contained native executable is specific to each individual operating systems and machine architecture that does not require a JVM. #### Java on Truffle -[Java on Truffle](/reference-manual/java-on-truffle/) is an implementation of the Java Virtual Machine Specification, built with the [Truffle language implementation framework](/graalvm-as-a-platform/language-implementation-framework/). +[Java on Truffle](reference-manual/java-on-truffle/README.md) is an implementation of the Java Virtual Machine Specification, built with the [Truffle language implementation framework](../truffle/docs/README.md). It is a complete Java VM that includes all core components, implements the same API as the Java Runtime Environment library, and reuses all JARs and native libraries from GraalVM. Java on Trufle is an experimental technology in GraalVM, available as of version 21.0.0. @@ -55,9 +55,9 @@ GraalVM is available as **GraalVM Enterprise** and **GraalVM Community** edition GraalVM Enterprise is based on Oracle JDK while GraalVM Community is based on OpenJDK. GraalVM is available for Linux, macOS, and Windows platforms on x86 64-bit systems, and for Linux on ARM 64-bit system. -The GraalVM distribution based on Oracle JDK 16 is experimental with [several known limitations](/release-notes/known-issues/). +The GraalVM distribution based on Oracle JDK 17 is experimental with [several known limitations](https://www.graalvm.org/release-notes/known-issues/). Depending on the platform, the distributions are shipped as *.tar.gz* or *.zip* archives. -See the [Getting Started guide](/docs/getting-started/) for installation instructions. +See the [Getting Started guide](getting-started/graalvm-community/get-started-graalvm-community.md) for installation instructions. ## Distribution Components List @@ -77,24 +77,24 @@ The core components enable using GraalVM as a runtime platform for programs writ **Utilities** * JavaScript REPL with the JavaScript interpreter * `lli` tool to directly execute programs from LLVM bitcode -* [GraalVM Updater](/reference-manual/graalvm-updater/) to install additional functionalities +* [GraalVM Updater](reference-manual/graalvm-updater.md) to install additional functionalities ### Additional Components GraalVM core installation can be extended with more languages runtimes and utilities. Tools/Utilities: -* [Native Image](/reference-manual/native-image/) -- a technology to compile an application ahead-of-time into a native executable. -* [LLVM toolchain](/reference-manual/llvm/) -- a set of tools and APIs for compiling native programs to bitcode that can be executed with on the GraalVM runtime. -* [Java on Truffle](/reference-manual/java-on-truffle/) -- a JVM implementation built upon the [Truffle framework](/graalvm-as-a-platform/language-implementation-framework/) to run Java via a Java bytecode interpreter. +* [Native Image](reference-manual/native-image/README.md) -- a technology to compile an application ahead-of-time into a native executable. +* [LLVM toolchain](reference-manual/llvm/README.md) -- a set of tools and APIs for compiling native programs to bitcode that can be executed with on the GraalVM runtime. +* [Java on Truffle](reference-manual/java-on-truffle/README.md) -- a JVM implementation built upon the [Truffle framework](../truffle/docs/README.md) to run Java via a Java bytecode interpreter. Runtimes: -* [Node.js](/reference-manual/js/) -- the Node.js 14.16.1 runtime for JavaScript -* [Python](/reference-manual/python/) -- Python 3.8.5 compatible -* [Ruby](/reference-manual/ruby/) -- Ruby 2.7.3 compatible -* [R](/reference-manual/r/) -- GNU R 4.0.3 compatible -* [GraalWasm](/reference-manual/wasm/) -- WebAssembly (Wasm) +* [Node.js](reference-manual/js/README.md) -- the Node.js 14.17.6 runtime for JavaScript +* [Python](reference-manual/python/README.md) -- Python 3.8.5 compatible +* [Ruby](reference-manual/ruby/README.md) -- Ruby 2.7.3 compatible +* [R](reference-manual/r/README.md) -- GNU R 4.0.3 compatible +* [GraalWasm](reference-manual/wasm/README.md) -- WebAssembly (Wasm) ## Licensing and Support @@ -126,11 +126,11 @@ The following table lists production-ready and experimental features in GraalVM ## What to Read Next -Whether you are new to GraalVM or have little experience using it, continue to [Get Started with GraalVM](/docs/getting-started/). +Whether you are new to GraalVM or have little experience using it, continue to [Get Started with GraalVM](getting-started/graalvm-community/get-started-graalvm-community.md). Install GraalVM on your local machine, try running the examples provided in the guide, or test GraalVM with your workload. -After that we suggest you to look at more complex [Examples Applications](/examples/). +After that we suggest you to look at more complex [Examples Applications](examples/examples.md). -Developers who have GraalVM already installed or have experience using, can skip the getting started guide and proceed to the [Reference Manuals](/reference-manual/) for in-depth coverage of GraalVM technologies. +Developers who have GraalVM already installed or have experience using, can skip the getting started guide and proceed to the [Reference Manuals](reference-manual/reference-manuals.md) for in-depth coverage of GraalVM technologies. To start coding with the GraalVM Polyglot APIs, check out the [GraalVM SDK Java API Reference](http://www.graalvm.org/sdk/javadoc). diff --git a/docs/reference-manual/compiler.md b/docs/reference-manual/compiler.md index 66da06569e70..f93031063447 100644 --- a/docs/reference-manual/compiler.md +++ b/docs/reference-manual/compiler.md @@ -27,7 +27,7 @@ The GraalVM compiler assures performance advantages for highly-abstracted progra Code using more abstraction and modern Java features like Streams or Lambdas will see greater speedups. Low-level code or code that converges to things like I/O, memory allocation, or garbage collection will see less improvement. Consequently, an application running on GraalVM needs to spend less time doing memory management and garbage collection. -For more information on performance tuning, refer to [Compiler Configuration on JVM](/reference-manual/java/options/). +For more information on performance tuning, refer to [Compiler Configuration on JVM](java/Options.md). ## Graph Compilation @@ -37,22 +37,20 @@ A *graph* was selected for this role. The graph can represent similar statements of different languages in the same way, like "if" statements or loops, which makes it possible to mix languages in the same program. The GraalVM compiler can then perform language-independent optimization and generate machine code on this graph. -GraalVM also includes the [Truffle language implementation framework](/graalvm-as-a-platform/language-implementation-framework/) -- a library, written in Java -- to build interpreters for programming languages, which then run on GraalVM. +GraalVM also includes the [Truffle language implementation framework](../../truffle/docs/README.md) -- a library, written in Java -- to build interpreters for programming languages, which then run on GraalVM. These languages can consequently benefit from the optimization possibilities of the GraalVM compiler. The pipeline for such compilation is: -* The Truffle framework code and data (Abstract Syntax Trees) is partially evaluated to -produce a compilation graph. When such an Abstract Syntax Tree (AST) is -hot (i.e., called many times), it is scheduled for compilation by the compiler. +* The Truffle framework code and data (Abstract Syntax Trees) is partially evaluated to produce a compilation graph. When such an Abstract Syntax Tree (AST) is hot (i.e., called many times), it is scheduled for compilation by the compiler. * The compilation graph is optimized by the GraalVM compiler to produce machine code. * JVMCI installs this machine code in the VM's code cache. * The AST will automatically redirect execution to the installed machine code once it is available. ## Ahead-of-time Compilation -Besides the Truffle framework, GraalVM incorporates its optimizing compiler into an advanced ahead-of-time (AOT) compilation technology -- [Native Image](/reference-manual/native-image/) -- which translates Java and JVM-based code into a native platform executable. +Besides the Truffle framework, GraalVM incorporates its optimizing compiler into an advanced ahead-of-time (AOT) compilation technology -- [Native Image](native-image/README.md) -- which translates Java and JVM-based code into a native platform executable. These native executables start nearly instantaneously, are smaller, and consume less resources of the same Java application, making them ideal for cloud deployments and microservices. -For more information about AOT compilation, go to [Native Image](/reference-manual/native-image/). +For more information about AOT compilation, go to [Native Image](native-image/README.md). ## Compiler Operating Modes @@ -80,7 +78,7 @@ This will produce diagnostic data for every method compiled by the compiler. To refine the set of methods for which diagnostic data is produced, use the `-Dgraal.MethodFilter=.` option. For example, `-Dgraal.MethodFilter=java.lang.String.*,HashMap.get` will produce diagnostic data only for methods in the `java.lang.String` class as well as methods named `get` in a class whose non-qualified name is `HashMap`. -Instead of being written to a file, diagnostic data can also be sent over the network to the [Ideal Graph Visualizer](/tools/igv/). +Instead of being written to a file, diagnostic data can also be sent over the network to the [Ideal Graph Visualizer](../tools/ideal-graph-visualizer.md). This requires the `-Dgraal.PrintGraph=Network` option, upon which the compiler will try to send diagnostic data to _127.0.0.1:4445_. This network endpoint can be configured with the `-Dgraal.PrintGraphHost` and `-Dgraal.PrintGraphPort` options. diff --git a/docs/reference-manual/embedding/embed-languages.md b/docs/reference-manual/embedding/embed-languages.md index 24bc455db339..a05b71bd6603 100644 --- a/docs/reference-manual/embedding/embed-languages.md +++ b/docs/reference-manual/embedding/embed-languages.md @@ -17,26 +17,22 @@ permalink: /reference-manual/embed-languages/ * [Build Native Images from Polyglot Applications](#build-native-images-from-polyglot-applications) * [Code Caching Across Multiple Contexts](#code-caching-across-multiple-contexts) * [Embed languages in Guest Languages](#embed-languages-in-guest-languages) -* [Step Through with Execution Listeners](#step-through-with-execution-listeners) * [Build a Shell for Many Languages](#build-a-shell-for-many-languages) -* [Configure Sandbox Resource Limits](#configure-sandbox-resource-limits) - +* [Step Through with Execution Listeners](#step-through-with-execution-listeners) +* [Enterprise Sandbox Resource Limits](#enterprise-sandbox-resource-limits) The GraalVM Polyglot API lets you embed and run code from guest languages in JVM-based host applications. -Throughout this section, you will learn how to create a host application in Java that -runs on GraalVM and directly calls a guest language. You can use the tabs -beneath each code example to choose between JavaScript, R, Ruby, and Python. +Throughout this section, you will learn how to create a host application in Java that runs on GraalVM and directly calls a guest language. +You can use the tabs beneath each code example to choose between JavaScript, R, Ruby, and Python. Ensure you set up GraalVM before you begin. ## Compile and Run a Polyglot Application -GraalVM can run polyglot applications written in any language implemented with the [Truffle language implementation framework](/graalvm-as-a-platform/language-implementation-framework/). +GraalVM can run polyglot applications written in any language implemented with the [Truffle language implementation framework](../../../truffle/docs/README.md). These languages are henceforth referenced as **guest languages**. -Complete the steps in this section to create a sample polyglot -application that runs on GraalVM and demonstrates programming language -interoperability. +Complete the steps in this section to create a sample polyglot application that runs on GraalVM and demonstrates programming language interoperability. 1. Create a `hello-polyglot` project directory. @@ -67,10 +63,8 @@ GraalVM. 4. Run `java HelloPolyglot` to run the application on GraalVM. -You now have a polyglot application that consists of a Java host application -and guest language code that run on GraalVM. You can use this application with -other code examples to demonstrate more advanced capabilities of the -Polyglot API. +You now have a polyglot application that consists of a Java host application and guest language code that run on GraalVM. +You can use this application with other code examples to demonstrate more advanced capabilities of the Polyglot API. To use other code examples in this section, you simply need to do the following: @@ -80,12 +74,9 @@ To use other code examples in this section, you simply need to do the following: ## Define Guest Language Functions as Java Values -Polyglot applications let you take values from one programming language and -use them with other languages. +Polyglot applications let you take values from one programming language and use them with other languages. -Use the code example in this section with your polyglot application to show -how the Polyglot API can return JavaScript, R, Ruby, or Python functions as -Java values. +Use the code example in this section with your polyglot application to show how the Polyglot API can return JavaScript, R, Ruby, or Python functions as Java values. {% include snippet-tabs @@ -106,12 +97,10 @@ executed. ## Access Guest Languages Directly from Java -Polyglot applications can readily access most language types and are not -limited to functions. Host languages, such as Java, can directly access guest -language values embedded in the polyglot application. +Polyglot applications can readily access most language types and are not limited to functions. +Host languages, such as Java, can directly access guest language values embedded in the polyglot application. -Use the code example in this section with your polyglot application to show -how the Polyglot API can access objects, numbers, strings, and arrays. +Use the code example in this section with your polyglot application to show how the Polyglot API can access objects, numbers, strings, and arrays. {% include snippet-tabs @@ -145,17 +134,13 @@ R where indices start with one. ## Access Java from Guest Languages -Polyglot applications offer bi-directional access between guest languages and -host languages. As a result, you can pass Java objects to guest languages. +Polyglot applications offer bi-directional access between guest languages and host languages. +As a result, you can pass Java objects to guest languages. -Use the code example in this section with your polyglot application to show how -guest languages can access primitive Java values, objects, arrays, and -functional interfaces. +Use the code example in this section with your polyglot application to show how guest languages can access primitive Java values, objects, arrays, and functional interfaces. -To permit guest languages to access any public method or field of a Java -object, set `allowAllAccess(true)` when the context is built. In this mode, the guest -language code must be fully trusted, as it can access other not explicitly exported Java methods -using reflection. +To permit guest languages to access any public method or field of a Java object, set `allowAllAccess(true)` when the context is built. +In this mode, the guest language code must be fully trusted, as it can access other not explicitly exported Java methods using reflection. {% include snippet-tabs @@ -193,11 +178,9 @@ that the script returns a `boolean` value of `true` as a result. ## Lookup Java Types from Guest Languages -In addition to passing Java objects to the guest language, it is possible -to allow the lookup of Java types in the guest language. +In addition to passing Java objects to the guest language, it is possible to allow the lookup of Java types in the guest language. -Use the code example in this section with your polyglot application to show how -guest languages lookup Java types and instantiate them. +Use the code example in this section with your polyglot application to show how guest languages lookup Java types and instantiate them. {% include snippet-tabs @@ -221,14 +204,11 @@ JavaScript using the `new` keyword. ## Computed Arrays Using Polyglot Proxies -The Polyglot API includes polyglot proxy interfaces that let you -customize Java interoperability by mimicking guest language types, such as -objects, arrays, native objects, or primitives. +The Polyglot API includes polyglot proxy interfaces that let you customize Java interoperability by mimicking guest language types, such as objects, arrays, native objects, or primitives. -Use the code example in this section with your polyglot application to see how -you can implement arrays that compute their values lazily. +Use the code example in this section with your polyglot application to see how you can implement arrays that compute their values lazily. -Note: The Polyglot API supports polyglot proxies either on the JVM or in Native Image. +> Note: The Polyglot API supports polyglot proxies either on the JVM or in Native Image. {% include snippet-tabs @@ -255,24 +235,20 @@ then returned. Note that array indices from 1-based languages such as R are converted to 0-based indices for proxy arrays. - The result of the language script is returned as a long value and verified. -For more information about the polyglot proxy interfaces, see the -[Polyglot API JavaDoc](http://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/package-summary.html). +For more information about the polyglot proxy interfaces, see the [Polyglot API JavaDoc](http://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/package-summary.html). ## Host Access The Polyglot API by default restricts access to certain critical functionality, such as file I/O. These restrictions can be lifted entirely by setting `allowAllAccess` to `true`. -Note: The access restrictions are currently only supported with JavaScript. +> Note: The access restrictions are currently only supported with JavaScript. ### Controlling Access to Host Functions It might be desireable to limit the access of guest applications to the host. -For example, if a Java method is exposed that calls `System.exit` then the guest -application will be able to exit the host process. -In order to avoid accidentally exposed methods, no host access is allowed by -default and every public method or field needs to be annotated with -`@HostAccess.Export` explicitly. +For example, if a Java method is exposed that calls `System.exit` then the guest application will be able to exit the host process. +In order to avoid accidentally exposed methods, no host access is allowed by default and every public method or field needs to be annotated with `@HostAccess.Export` explicitly. {% include snippet-tabs @@ -394,7 +370,7 @@ The following access parameters may be configured: * Allow access to native APIs using [`allowNativeAccess`](https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/Context.Builder.html#allowNativeAccess-boolean-). * Allow access to IO using [`allowIO`](https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/Context.Builder.html#allowIO-boolean-) and proxy file accesses using [`fileSystem`](https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/Context.Builder.html#fileSystem-org.graalvm.polyglot.io.FileSystem-). -Note: Granting access to class loading, native APIs, or host I/O effectively grants all access, as these privileges can be used to bypass other access restrictions. +> Note: Granting access to class loading, native APIs, or host I/O effectively grants all access, as these privileges can be used to bypass other access restrictions. ## Build Native Images from Polyglot Applications @@ -493,7 +469,7 @@ Caching may be disabled explicitly by setting [cached(boolean cached)](https:// Consider the following code snippet as an example: -``` +```java public class Main { public static void main(String[] args) { try (Engine engine = Engine.create()) { @@ -543,12 +519,12 @@ public class Main { public static void main(String[] args) { try (Context outer = Context.newBuilder() .allowAllAccess(true) - .build()) { + .build()) { outer.eval("js", "inner = Java.type('org.graalvm.polyglot.Context').create()"); outer.eval("js", "value = inner.eval('js', '({data:42})')"); int result = outer.eval("js", "value.data").asInt(); outer.eval("js", "inner.close()"); - + System.out.println("Valid " + (result == 42)); } } @@ -566,8 +542,7 @@ In this code:
 ## Build a Shell for Many Languages -With just a few lines of code, the GraalVM Polyglot API lets you build -applications that integrate with any guest language supported by GraalVM. +With just a few lines of code, the GraalVM Polyglot API lets you build applications that integrate with any guest language supported by GraalVM. This shell implementation is agnostic to any particular guest language. @@ -600,12 +575,11 @@ for (;;) { } ``` - - ## Step Through with Execution Listeners -The GraalVM Polyglot API allows users to instrument the execution of guest languages through [ExecutionListener class](http://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/management/ExecutionListener.html). For example, it lets you attach an execution listener that is invoked for every statement of the guest language program. Execution listeners -are designed as simple API for polyglot embedders and may become handy in, e.g., single-stepping through the program. +The GraalVM Polyglot API allows users to instrument the execution of guest languages through [ExecutionListener class](http://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/management/ExecutionListener.html). +For example, it lets you attach an execution listener that is invoked for every statement of the guest language program. +Execution listeners are designed as simple API for polyglot embedders and may become handy in, e.g., single-stepping through the program. ```java import org.graalvm.polyglot.*; @@ -635,5 +609,5 @@ In this code: - The `context.eval()` call evaluates a specified snippet of guest language code. - The `listener.close()` closes a listener earlier, however execution listeners are automatically closed with the engine. - + {% include_relative sandbox-options.md %} diff --git a/docs/reference-manual/embedding/sandbox-options.md b/docs/reference-manual/embedding/sandbox-options.md index 116e08e0aef6..f0ca0be8f92c 100644 --- a/docs/reference-manual/embedding/sandbox-options.md +++ b/docs/reference-manual/embedding/sandbox-options.md @@ -1,14 +1,14 @@ ## Enterprise Sandbox Resource Limits -The 20.3 release of GraalVM introduced the experimental Sandbox Resource Limits feature that allows for the limiting of resources used by guest applications. -These resource limits are not available in the community edition of GraalVM. -The following document describes how to configure sandbox resource limits using options in the polyglot API +GraalVM Enterprise provides the experimental Sandbox Resource Limits feature that allows for the limiting of resources used by guest applications. +These resource limits are not available in the Community Edition of GraalVM. +The following document describes how to configure sandbox resource limits using options in GraalVM Polyglot API. -In general all resource limit options are prefixed with `sandbox` option group and they can be listed using the help of any language launcher provided in GraalVM e.g. `js --help:tools`. +In general all resource limit options are prefixed with `sandbox` option group and they can be listed using the help of any language launcher provided in GraalVM, e.g., `js --help:tools`. Polyglot options can be provided through the language launcher, using the polyglot embedding API of the Graal SDK, or on the JVM using a system property. -For better understanding of the examples it is recommended to read the [polyglot embedding guide](/reference-manual/embed-languages/) of the reference manual first. +For better understanding of the examples it is recommended to read the [polyglot embedding guide](embed-languages.md) of the reference manual first. -Currently all sandbox options are experimental therefore in these examples it is assumed that experimental options are enabled (e.g. with `--experimental-options`). +Currently all sandbox options are experimental therefore in these examples it is assumed that experimental options are enabled (e.g., with `--experimental-options`). The options are a best effort approach to limiting resource usage of guest applications. The resource limits may be configured using the following options: @@ -31,7 +31,8 @@ The resource limits may be configured using the following options: Different configurations may be provided for each polyglot embedding `Context` instance. In addition to that the limits may be reset at any point of time during the execution. Resetting is only aplicable to `sandbox.MaxStatements` and `sandbox.MaxCPUTime`. -A guest language might choose to create an inner context within the outer execution context. The limits are applied to the outer context and all inner contexts it spawns. It is not possible to specify a separate limit for inner contexts and it is also not possible to escape any limit by creating an inner context. +A guest language might choose to create an inner context within the outer execution context. The limits are applied to the outer context and all inner contexts it spawns. +It is not possible to specify a separate limit for inner contexts and it is also not possible to escape any limit by creating an inner context. ## Limiting the active CPU time @@ -60,7 +61,7 @@ It is not allowed specify negative values or no time unit with CPU time limit op ### Example Usage -``` +```java try (Context context = Context.newBuilder("js") .allowExperimentalOptions(true) .option("sandbox.MaxCPUTime", "500ms") @@ -84,9 +85,10 @@ try (Context context = Context.newBuilder("js") Specifies the maximum number of statements a context may execute until the the context will be cancelled. After the statement limit was triggered for a context, it is no longer usable and every use of the context will throw a `PolyglotException` that returns `true` for `PolyglotException.isCancelled()`. The statement limit is independent of the number of threads executing and is applied per context. -It is also possible to specify this limit using the [ResourceLimits]() API of the polyglot embedding API. +It is also possible to specify this limit using the `[ResourceLimits]()` API of the polyglot embedding API. -By default there is no statement limit applied. The limit may be set to a negative number to disable it. +By default there is no statement limit applied. +The limit may be set to a negative number to disable it. Whether this limit is applied internal sources only can be configured using `sandbox.MaxStatementsIncludeInternal`. By default the limit does not include statements of sources that are marked internal. If a shared engine is used then the same internal configuration must be used for all contexts of an engine. @@ -100,8 +102,7 @@ The complexity of a single statement may not be constant time depending on the g For example, statements that execute JavaScript builtins, like `Array.sort`, may account for a single statement, but its execution time is dependent on the size of the array. The statement count limit is therefore not suitable to perform time boxing and must be combined with other more reliable measures like the CPU time limit. - -``` +```java try (Context context = Context.newBuilder("js") .allowExperimentalOptions(true) .option("sandbox.MaxStatements", "2") @@ -144,20 +145,21 @@ If used together with the AST depth limit it can be used to estimate total stack Limits the number of threads that can be used by a context at the same point in time. By default, an arbitary number of threads can be used. -If a set limit is exceeded, entering the context fails with a PolyglotException and the polyglot context is canceled. +If a set limit is exceeded, entering the context fails with a `PolyglotException` and the polyglot context is canceled. Resetting resource limits does not affect thread limits. ## Limiting the maximum heap memory The `sandbox.MaxHeapMemory` option allows you to specify the maximum heap memory the application is allowed to retain during its run. -`sandbox.MaxHeapMemory` must be positive. This option is only supported on a HotSpot-based VM. Enabling this option in AOT mode will result in PolyglotException. +`sandbox.MaxHeapMemory` must be positive. This option is only supported on a HotSpot-based VM. +Enabling this option in AOT mode will result in PolyglotException. When exceeding of the limit is detected, the corresponding context is automatically cancelled and then closed. The efficacy of this option (also) depends on the garbage collector used. #### Example Usage -``` +```java try (Context context = Context.newBuilder("js") .allowExperimentalOptions(true) .option("sandbox.MaxHeapMemory", "100MB") @@ -177,43 +179,53 @@ try (Context context = Context.newBuilder("js") #### Implementation details and expert options -The limit is checked by retained size computation triggered either based on [allocated](https://docs.oracle.com/en/java/javase/11/docs/api/jdk.management/com/sun/management/ThreadMXBean.html#getThreadAllocatedBytes\(long\)) bytes or on -[low memory notification](https://docs.oracle.com/en/java/javase/11/docs/api/java.management/java/lang/management/MemoryMXBean.html). +The limit is checked by retained size computation triggered either based on [allocated](https://docs.oracle.com/en/java/javase/11/docs/api/jdk.management/com/sun/management/ThreadMXBean.html#getThreadAllocatedBytes\(long\)) bytes or on [low memory notification](https://docs.oracle.com/en/java/javase/11/docs/api/java.management/java/lang/management/MemoryMXBean.html). -The allocated bytes are checked by a separate high-priority thread that will be woken regularly. There is one such thread for each memory-limited context (one with `sandbox.MaxHeapMemory` set). -The retained bytes computation is done by yet another high-priority thread that is started from the allocated bytes checking thread as needed. The retained bytes computation thread also cancels the context if the heap memory limit is exeeded. Additionaly, when low memory trigger is invoked, -all contexts on engines with at least one memory-limited context are paused together with their allocation checkers. All individual retained size computations are cancelled. -Retained bytes in the heap for each memory-limited context are computed by a single high-priority thread. Contexts exceeding their limits are cancelled, and then the execution is resumed. +The allocated bytes are checked by a separate high-priority thread that will be woken regularly. +There is one such thread for each memory-limited context (one with `sandbox.MaxHeapMemory` set). +The retained bytes computation is done by yet another high-priority thread that is started from the allocated bytes checking thread as needed. +The retained bytes computation thread also cancels the context if the heap memory limit is exeeded. +Additionaly, when low memory trigger is invoked, all contexts on engines with at least one memory-limited context are paused together with their allocation checkers. +All individual retained size computations are cancelled. +Retained bytes in the heap for each memory-limited context are computed by a single high-priority thread. +Contexts exceeding their limits are cancelled, and then the execution is resumed. The main goal of the heap memory limits is to prevent heap memory depletion related errors in most cases and thus enable the host VM to run smoothly even in the presence of misbehaving contexts. -The implementation is best effort. This means that there is no guarantee on the accuracy of the heap memory limit. There is also no guarantee that setting a heap memory limit will prevent the context from causing `OutOfMemory` errors. +The implementation is best effort. This means that there is no guarantee on the accuracy of the heap memory limit. +There is also no guarantee that setting a heap memory limit will prevent the context from causing `OutOfMemory` errors. Guest applications that allocate many objects in quick succession have a lower accuracy than applications which allocate objects rarely. -The guest code execution will only be paused if the host heap memory is exhausted and a low memory trigger of the host VM is invoked. Note that the scope of the pause is an engine, so a context without the `sandbox.MaxHeapMemory` option set is also paused in case it shares the engine with other context that is memory-limited. +The guest code execution will only be paused if the host heap memory is exhausted and a low memory trigger of the host VM is invoked. +Note that the scope of the pause is an engine, so a context without the `sandbox.MaxHeapMemory` option set is also paused in case it shares the engine with other context that is memory-limited. Also note that if one context is cancelled other contexts with the same explicit engine may be slowed down. How the size retained by a context is computed can be customized using the expert options `sandbox.AllocatedBytesCheckInterval`, `sandbox.AllocatedBytesCheckEnabled`, `sandbox.AllocatedBytesCheckFactor`, `sandbox.RetainedBytesCheckInterval`, `sandbox.RetainedBytesCheckFactor`, and `sandbox.UseLowMemoryTrigger` described below. -Retained size computation for a context is triggered when a retained bytes estimate exceeds a certain factor of specified `sandbox.MaxHeapMemory`. The estimate is based on heap memory +Retained size computation for a context is triggered when a retained bytes estimate exceeds a certain factor of specified `sandbox.MaxHeapMemory`. +The estimate is based on heap memory [allocated](https://docs.oracle.com/en/java/javase/11/docs/api/jdk.management/com/sun/management/ThreadMXBean.html#getThreadAllocatedBytes\(long\)) by threads where the context has been active. More precisely, the estimate is the result of previous retained bytes computation, if available, plus bytes allocated since the start of the previous computation. -By default the factor of `sandbox.MaxHeapMemory` is 1.0 and it can be customized by the `sandbox.AllocatedBytesCheckFactor` option. The factor must be positive. -For example, let `sandbox.MaxHeapMemory` be 100MB and `sandbox.AllocatedBytesCheckFactor` be 0.5. The retained size computation is first triggered when allocated bytes reach 50MB. +By default the factor of `sandbox.MaxHeapMemory` is 1.0 and it can be customized by the `sandbox.AllocatedBytesCheckFactor` option. +The factor must be positive. +For example, let `sandbox.MaxHeapMemory` be 100MB and `sandbox.AllocatedBytesCheckFactor` be 0.5. +The retained size computation is first triggered when allocated bytes reach 50MB. Let the computed retained size be 25MB, then the next retained size computation is triggered when additional 25MB is allocated, etc. -By default, allocated bytes are checked every 10 milliseconds. This can be configured by `sandbox.AllocatedBytesCheckInterval`. The smallest possible interval is 1ms. Any smaller value is interpreted as 1ms. +By default, allocated bytes are checked every 10 milliseconds. This can be configured by `sandbox.AllocatedBytesCheckInterval`. +The smallest possible interval is 1ms. Any smaller value is interpreted as 1ms. The beginnings of two retained size computations of the same context must be by default at least 10 milliseconds apart. This can be configured by the `sandbox.RetainedBytesCheckInterval` option. The interval must be positive. -The allocated bytes checking for a context can be disabled by the `sandbox.AllocatedBytesCheckEnabled` option. By default it is enabled ("true"). If disabled ("false"), -retained size checking for the context can be triggered only by the low memory trigger. +The allocated bytes checking for a context can be disabled by the `sandbox.AllocatedBytesCheckEnabled` option. +By default it is enabled ("true"). If disabled ("false"), retained size checking for the context can be triggered only by the low memory trigger. When the total number of bytes allocated in the heap for the whole host VM exceeds a certain factor of the total heap memory of the VM, [low memory notification](https://docs.oracle.com/en/java/javase/11/docs/api/java.management/java/lang/management/MemoryMXBean.html) is invoked and initiates the following process. -The execution for all engines with at least one execution context which has the `sandbox.MaxHeapMemory` option set is paused, -retained bytes in the heap for each memory-limited context are computed, contexts exceeding their limits are cancelled, and then the execution is resumed. -The default factor is 0.7. This can be configuted by the `sandbox.RetainedBytesCheckFactor` option. The factor must be between 0.0 and 1.0. All contexts using the `sandbox.MaxHeapMemory` option must use the same value for `sandbox.RetainedBytesCheckFactor`. +The execution for all engines with at least one execution context which has the `sandbox.MaxHeapMemory` option set is paused, retained bytes in the heap for each memory-limited context are computed, contexts exceeding their limits are cancelled, and then the execution is resumed. +The default factor is 0.7. This can be configuted by the `sandbox.RetainedBytesCheckFactor` option. +The factor must be between 0.0 and 1.0. All contexts using the `sandbox.MaxHeapMemory` option must use the same value for `sandbox.RetainedBytesCheckFactor`. -The described low memory trigger can be disabled by the `sandbox.UseLowMemoryTrigger` option. By default it is enabled ("true"). If disabled ("false"), -retained size checking for the execution context can be triggered only by the allocated bytes checker. All contexts using the `sandbox.MaxHeapMemory` option must use the same value for `sandbox.UseLowMemoryTrigger`. +The described low memory trigger can be disabled by the `sandbox.UseLowMemoryTrigger` option. +By default it is enabled ("true"). If disabled ("false"), retained size checking for the execution context can be triggered only by the allocated bytes checker. +All contexts using the `sandbox.MaxHeapMemory` option must use the same value for `sandbox.UseLowMemoryTrigger`. If exceeding of the heap memory limit is detected then the polyglot context is cancelled and the execution stops by throwing a [`PolyglotException`](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/PolyglotException.html) which returns `true` for `isResourceExhausted()`. As soon as the memory limit is triggered, no further application code can be executed with this context. @@ -234,7 +246,7 @@ This can be useful if a known and trusted initialization script should be exclud ### Example Usage -``` +```java try (Context context = Context.newBuilder("js") .allowExperimentalOptions(true) .option("sandbox.MaxCPUTime", "500ms") diff --git a/docs/reference-manual/graalvm-updater.md b/docs/reference-manual/graalvm-updater.md index abf06080ab1a..e1495dcfde50 100644 --- a/docs/reference-manual/graalvm-updater.md +++ b/docs/reference-manual/graalvm-updater.md @@ -7,15 +7,6 @@ permalink: /reference-manual/graalvm-updater/ # GraalVM Updater -GraalVM Updater, `gu`, is a command-line utility to install and manage optional GraalVM language runtimes and utilities. -Each of these language runtimes and utilities must be downloaded and installed separately. -To assist you with the installation, these are pre-packaged as JAR files and referenced in the documentation as "components". -As of version 21.0.0, GraalVM Updater has become more efficient, and can be used to update your local GraalVM installation to a newer version or upgrade from a Community to Enterprise Edition. -Read more in [Upgrade GraalVM](#upgrade-graalvm). - -GraalVM Updater is included in the base GraalVM distribution and can be used with the `/bin/gu` launcher. -The source code of GraalVM Updater is located in the `/lib/installer` folder. - * [Component Installation](#component-installation) * [Component Uninstallation](#component-uninstallation) * [Upgrade GraalVM](#upgrade-graalvm) @@ -25,22 +16,31 @@ The source code of GraalVM Updater is located in the `/lib/installer` f * [Configure Proxies](#configure-proxies) * [Replace Components and Files](#replace-components-and-files) +GraalVM Updater, `gu`, is a command-line utility to install and manage optional GraalVM language runtimes and utilities. +Each of these language runtimes and utilities must be downloaded and installed separately. +To assist you with the installation, they are pre-packaged as JAR files and referenced in the documentation as "components". +GraalVM Updater can be also used to update your local GraalVM installation to a newer version or upgrade from a Community to Enterprise Edition. +Read more in [Upgrade GraalVM](#upgrade-graalvm). + +GraalVM Updater is included in the base GraalVM distribution and can be used with the `/bin/gu` launcher. +The source code of GraalVM Updater is located in the `/lib/installer` folder. + ## Component Installation The following GraalVM language runtimes and utilities are available for installation. Tools/Utilities: -* [Native Image](/native-image/README.md) -- a technology to compile an application ahead-of-time into a native executable -* [LLVM toolchain](/llvm/README.md) -- a set of tools and APIs for compiling native programs to bitcode that can be executed on GraalVM -* [Java on Truffle](/java-on-truffle/README.md) -- a Java Virtual Machine implementation based on a Truffle interpreter for GraalVM +* [Native Image](native-image/README.md) -- a technology to compile an application ahead-of-time into a native executable +* [LLVM toolchain](llvm/README.md) -- a set of tools and APIs for compiling native programs to bitcode that can be executed on GraalVM Runtimes: -* [Node.js](/reference-manual/js/) -- Node.js 14.16.1 compatible -* [Python](/python/README.md) -- Python 3.8.5-compatible -* [Ruby](/ruby/README.md) -- Ruby 2.7.3-compatible -* [R](/r/README.md) -- GNU R 4.0.3-compatible -* [Wasm](/wasm/README.md) -- WebAssembly (Wasm) +* [Java on Truffle](java-on-truffle/README.md) -- a Java Virtual Machine implementation based on a Truffle interpreter for GraalVM +* [Node.js](js/README.md) -- Node.js 14.16.1 compatible +* [Python](python/README.md) -- Python 3.8.5-compatible +* [Ruby](ruby/README.md) -- Ruby 2.7.3-compatible +* [R](r/README.md) -- GNU R 4.0.3-compatible +* [Wasm](wasm/README.md) -- WebAssembly (Wasm) GraalVM Updater verifies whether or not the version of a component is appropriate for the current GraalVM installation. Components are released for each GraalVM distribution with respective updates, and those downloaded for previous release(s) cannot be used with newer ones. @@ -63,21 +63,15 @@ gu available ```shell gu install ruby ``` -GraalVM Updater first downloads the list of components, then uses the -information in the list to download the actual component package, then installs -it. To see more verbose output during the installation, like the download -progress bar, print versions, and dependency information, use the `-v` -(`--verbose`) switch. - -If a component being installed depends on another component, GraalVM Updater will -search the catalog to find an appropriate dependency and install it as well. If -the required components cannot be found, installation will fail. - -When using custom catalog URLs, it is possible, for a convenience, to set -the environment variable `GRAALVM_CATALOG` pointing to the custom catalog's URL. -GraalVM Updater will use the URL defined by `GRAALVM_CATALOG` in preference to -the builtin ones. You may setup the environment variable in startup or profile -scripts. +GraalVM Updater first downloads the list of components, then uses the information in the list to download the actual component package, then installs it. +To see more verbose output during the installation, like the download progress bar, print versions, and dependency information, use the `-v` (`--verbose`) switch. + +If a component being installed depends on another component, GraalVM Updater will search the catalog to find an appropriate dependency and install it as well. +If the required components cannot be found, installation will fail. + +When using custom catalog URLs, it is possible, for a convenience, to set the environment variable `GRAALVM_CATALOG` pointing to the custom catalog's URL. +GraalVM Updater will use the URL defined by `GRAALVM_CATALOG` in preference to the builtin ones. +You may setup the environment variable in startup or profile scripts. Note: If you need, for some reason to set the `GRAALVM_HOME` environment variable, it may affect `gu` operation. If it is set, it should point to the intended GraalVM installation, same as `JAVA_HOME` and `PATH`. @@ -92,7 +86,7 @@ gu -L install component.jar ``` For example, to install Native Image for Java 11 GraalVM Enterprise distribution on macOS, run: ```shell -gu -L install native-image-installable-svm-java11-darwin-amd64-.jar +gu -L install native-image-installable-svm-svmee-java11-darwin-amd64-.jar ``` The `-L` option, equivalent to `--local-file` or `--file`, installs a component from a downloaded JAR. @@ -112,12 +106,11 @@ GraalVM Updater can then use that folder instead of the catalog: gu install -C /path/to/downloads/directory ComponentId ``` -Specify the directory to use for the components collection. It is possible to type -a component's name (like `ruby`) instead of a filename. GraalVM Updater will also -attempt to find required dependencies in the local component collection. +Specify the directory to use for the components collection. +It is possible to type a component's name (like `ruby`) instead of a filename. +GraalVM Updater will also attempt to find required dependencies in the local component collection. -When installing components from a given directory, you can allow installing all -components which have the correct version number for GraalVM using wildcards: +When installing components from a given directory, you can allow installing all components which have the correct version number for GraalVM using wildcards: ```shell ./gu install -C ~/Download/Components/ native* ``` @@ -243,9 +236,8 @@ GraalVM Updater common options: * `-v, --verbose`: enable verbose output. Print versions and dependency information * `--version`: print version -Oracle GraalVM Enterprise Edition users might need to pass an -additional verification step to login to the Oracle components repository. GraalVM -Updater tool provides options for that: +Oracle GraalVM Enterprise Edition users might need to pass an additional verification step to login to the Oracle components repository. +GraalVM Updater tool provides options for that: * `--public-key / -k `: set the path to a custom GPG public key path * `--username/-U`: enter a username @@ -260,34 +252,24 @@ Runtime options: ## Configure Proxies -If GraalVM Updater needs to reach the component catalog, or download a component -package, it may need to pass through the HTTP/HTTPS proxy, if the network uses one. On -_macOS_, the proxy settings are automatically obtained from the OS. On _Linux_, -ensure that the `http_proxy` and `https_proxy` environment variables are set -appropriately before launching the `gu` tool. Refer to the distribution -and/or desktop environment documentation for the details. +If GraalVM Updater needs to reach the component catalog, or download a component package, it may need to pass through the HTTP/HTTPS proxy, if the network uses one. +On _macOS_, the proxy settings are automatically obtained from the OS. +On _Linux_, ensure that the `http_proxy` and `https_proxy` environment variables are set appropriately before launching the `gu` tool. +Refer to the distribution and/or desktop environment documentation for the details. -GraalVM Updater intentionally does not support an option to disable certificate -or hostname verification, for security reasons. A user may try to add a proxy's -certificate to the GraalVM default security trust store. A user can also -download a component manually to a folder, and then use `gu -L install /path/to/file` or `gu -C /path/to/download/dir install component` to install from a local filesystem. +GraalVM Updater intentionally does not support an option to disable certificate or hostname verification, for security reasons. +A user may try to add a proxy's certificate to the GraalVM default security trust store. +A user can also download a component manually to a folder, and then use `gu -L install /path/to/file` or `gu -C /path/to/download/dir install component` to install from a local filesystem. ### Working without Internet Access -If your machine cannot access and download the catalog and components from -the Internet, either because it is behind a proxy, or for security reasons, -GraalVM Updater can install components from a local directory, or a directory on -a network share accessible on the target machine. +If your machine cannot access and download the catalog and components from the Internet, either because it is behind a proxy, or for security reasons, GraalVM Updater can install components from a local directory, or a directory on a network share accessible on the target machine. -You need to prepare a directory, download all components that you want to install -and their dependencies (in case they require other GraalVM components to work) into -that directory. +You need to prepare a directory, download all components that you want to install and their dependencies (in case they require other GraalVM components to work) into that directory. -Then you can use `gu -L install /path/to/file` (where the `-L` option instructs to use local files, -equivalent to `--local-file` or `--file`). Adding the `-D` option will instruct GraalVM Updater -to look for potential dependencies in the directory next to the -installable file. Additionally, `gu -C /path/to/download/dir install component` can be used, with the specified -directory contents acting as a catalog of components. +Then you can use `gu -L install /path/to/file` (where the `-L` option instructs to use local files, equivalent to `--local-file` or `--file`). +Adding the `-D` option will instruct GraalVM Updater to look for potential dependencies in the directory next to the installable file. +Additionally, `gu -C /path/to/download/dir install component` can be used, with the specified directory contents acting as a catalog of components. Note that with `gu -L` you need to specify the component's file name, while when using `gu -C
    `, the component name must be used: ```shell @@ -300,13 +282,10 @@ gu -C /tmp/instalables install ruby ## Replace Components and Files -A component may be only installed once. GraalVM Updater refuses to install a -component if a component with the same ID is already installed. However, the -installed component can be replaced. GraalVM Updater first uninstalls the -component and then installs a new package. +A component may be only installed once. GraalVM Updater refuses to install a component if a component with the same ID is already installed. +However, the installed component can be replaced. GraalVM Updater first uninstalls the component and then installs a new package. -To replace a component, use the `-r` -option, and the `-L` (`--local-file` or `--file`) option to treat parameters as local filename of a packaged component: +To replace a component, use the `-r` option, and the `-L` (`--local-file` or `--file`) option to treat parameters as local filename of a packaged component: ```shell gu install -L -r component.jar gu install -r ruby @@ -314,18 +293,16 @@ gu install -r ruby The process is the same as if `gu remove` is run first and `gu install` next. -GraalVM Updater also refuses to overwrite existing files if the -to-be-installed and existing versions differ. There are cases when refreshing -file contents may be needed, such as if they were modified or damaged. In this case, use the `-o` option: +GraalVM Updater also refuses to overwrite existing files if the to-be-installed and existing versions differ. +There are cases when refreshing file contents may be needed, such as if they were modified or damaged. +In this case, use the `-o` option: ```shell gu install -L -o component.jar gu install -o ruby ``` -GraalVM Updater will then instruct the user to replace the contained files of a -component. By default, it will not alter anything. Alternatively, use the `-f` -(`--force`) option, which disables most of the checks, and allows the user to -install non-matching versions. +GraalVM Updater will then instruct the user to replace the contained files of a component. +By default, it will not alter anything. Alternatively, use the `-f` (`--force`) option, which disables most of the checks, and allows the user to install non-matching versions. ### Troubleshooting diff --git a/docs/reference-manual/java-on-truffle/Demos.md b/docs/reference-manual/java-on-truffle/Demos.md index 16f73280241d..d3194f58c4f1 100644 --- a/docs/reference-manual/java-on-truffle/Demos.md +++ b/docs/reference-manual/java-on-truffle/Demos.md @@ -131,7 +131,7 @@ GraalVM Native Image technology allows compiling applications ahead-of-time (AOT The main trade off for using Native Image is that the analysis and compilation of your program happens under the closed world assumption, meaning the static analysis needs to process all bytecode which will ever be executed in the application. This makes using some language features like dynamic class loading or reflection tricky. -Java on Truffle is a JVM implementation of a JVM bytecode interpreter, built on the [Truffle framework](/graalvm-as-a-platform/language-implementation-framework/). +Java on Truffle is a JVM implementation of a JVM bytecode interpreter, built on the [Truffle framework](../../../truffle/docs/README.md). It is essentially a Java application, as are the Truffle framework itself and the GraalVM JIT compiler. All three of them can be compiled ahead-of-time with `native-image`. Using Java on Truffle for some parts of your application makes it possible to isolate the required dynamic behaviour and still use the native image on the rest of your code. @@ -144,10 +144,9 @@ It is a REPL capable of evaluating Java code and consists of two parts: This design naturally fits the point we are trying to illustrate. We can build a native executable of the JShell's UI part, and make it include Java on Truffle to run the code dynamically specified at run time. Prerequisites: -* [GraalVM 21.0](/downloads/) -* [Native Image](/reference-manual/native-image/#install-native-image) -* [Java on Truffle](/reference-manual/java-on-truffle/#install-java-on-truffle) - +* [GraalVM 21.0](https://www.graalvm.org/downloads/) +* [Native Image](../native-image/README.md#install-native-image) +* [Java on Truffle](README.md#install-java-on-truffle) 1. Clone the [project](https://github.com/graalvm/graalvm-demos) with the demo applications and navigate to the `espresso-jshell` directory: diff --git a/docs/reference-manual/java-on-truffle/FAQ.md b/docs/reference-manual/java-on-truffle/FAQ.md index b54113ff9670..2999dbfef75f 100644 --- a/docs/reference-manual/java-on-truffle/FAQ.md +++ b/docs/reference-manual/java-on-truffle/FAQ.md @@ -10,17 +10,17 @@ permalink: /reference-manual/java-on-truffle/faq/ ### Does Java running on Truffle implement the Java language running as a Truffle interpreter? Not quite: it implements the Java Virtual Machine running as a Truffle interpreter. -That means it can only run a Java program once it has been compiled to Java bytecode (classes, JARs, etc.) with your favorite Java compiler (e.g., javac) or a build tool (Maven, Gradle, etc.). +That means it can only run a Java program once it has been compiled to Java bytecode (classes, JARs, etc.) with your favorite Java compiler (e.g., `javac`) or a build tool (Maven, Gradle, etc.). In the GraalVM family, this is similar to WebAssembly or the LLVM interpreter: while both can run C programs, they have to be complied by a C compiler first. ### Does Java running on Truffle run on HotSpot too? -Like other languages implemented with the [Truffle framework](/graalvm-as-a-platform/language-implementation-framework/), it can run both as a native image or on top of HotSpot. +Like other languages implemented with the [Truffle framework](../../../truffle/docs/README.md), it can run both as a native image or on top of HotSpot. Running on top of HotSpot is currently only possible on Linux. We plan to extend this capability to macOS and Windows platforms also. ### Does running Java on Truffle require HotSpot? No, it doesn't, it works fine as a native image. -Java on Truffle does require a standard core Java library (the `rt.jar` library for Java 8 or the `lib/modules` file for Java 11 as well as the associated native libraries: `libjava`, `libnio`, etc.) +Java on Truffle does require a standard core Java library (the `rt.jar` library for Java 8 or the `lib/modules` file for Java 11 and Java 17 as well as the associated native libraries: `libjava`, `libnio`, etc.) ### Running Java on GraalVM already brings the highest level of optimization, what benefits will Java on Truffle give me? - Java on Truffle will inherit the extensive tooling provided by the Truffle framework. This means that for the things like code coverage and profiling you would no longer need to rely on external tools. @@ -32,9 +32,8 @@ Java on Truffle does require a standard core Java library (the `rt.jar` library Java on Truffle is an implementation of the Java Virtual Machine. It is open source and is offered as free software under the [GNU General Public License version two (GPLv2)](https://github.com/oracle/graal/blob/master/tools/LICENSE). ### Can I run Java on Truffle in production? - Running in production is not recommended. -While Java on Truffle already passes the Java Compatibility Kit (JCK or TCK for Java SE) 8 and 11 runtimes, it is still an early prototype and experimental feature in GraalVM. +While Java on Truffle already passes the Java Compatibility Kit (JCK or TCK for Java SE) 8, 11 and 17 runtimes, it is still an early prototype and experimental feature in GraalVM. It may undergo significant improvements before being considered production-ready. ### What performance can I expect from executing Java on Truffle? @@ -43,7 +42,7 @@ It does not match the speed offered by GraalVM yet for sure, but having created ### Can I embed Java running on Truffle in my application? Yes, you can use [GraalVM's Polyglot API](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/package-summary.html) to run Java bytecodes in a separate context from the host Java VM. -You can even embed a Java 8 context in a Java 11 application! +You can even embed a Java 8 context in a Java 11 or Java 17 application! ### Why do I see "Unrecognized option: -javaagent:.../idea_rt.jar..." when I try to run my app from the IDE? Java on Truffle does not yet support attaching Java agents. For the time being add: `-XX:+IgnoreUnrecognizedVMOptions` to the VM options too. diff --git a/docs/reference-manual/java-on-truffle/HotSwapPluginAPI.md b/docs/reference-manual/java-on-truffle/HotSwapPluginAPI.md index 55891a5abf89..145c056976a3 100644 --- a/docs/reference-manual/java-on-truffle/HotSwapPluginAPI.md +++ b/docs/reference-manual/java-on-truffle/HotSwapPluginAPI.md @@ -7,7 +7,7 @@ permalink: /reference-manual/java-on-truffle/hotswap-plugin/ # Truffle on Java HotSwap Plugin API -With Java on Truffle you can benefit from enhanced HotSwap [capabilites](/reference-manual/java-on-truffle/demos/#enhanced-hotswap-capabilities-with-java-on-truffle) that allow the code to evolve naturally during development without the need for restarting a running application. +With Java on Truffle you can benefit from enhanced HotSwap [capabilites](Demos.md#enhanced-hotswap-capabilities-with-java-on-truffle) that allow the code to evolve naturally during development without the need for restarting a running application. ​ While code reloading (HotSwap) is a powerful tool, it is not sufficient to reflect all kinds of changes, e.g., changes to annotations, framework-specific changes such as implemented services or beans. For these things the code often needs to be executed to reload configurations or contexts before the changes are fully reflected in the running instance. @@ -18,7 +18,7 @@ The main design principle is that you can register various HotSwap listeners tha Examples include the ability to re-run a static initializer, a generic post HotSwap callback and hooks when implementations for a certain service provider changes. ​ **Note**: The HotSwap Plugin API is under development and more fine-grained registration of HotSwap listeners are likely to be added upon requests from the community. -You are welcomed to send enhancement requests to help shape the API through our community support [channels](/community/). +You are welcomed to send enhancement requests to help shape the API through our community support [channels](https://www.graalvm.org/community/). Review the HotSwap Plugin API by going through a running example that will enable more powerful reloading support on [Micronaut](https://micronaut.io/). ​ @@ -138,7 +138,7 @@ Here is a sample application created from the tutorial ["Creating your first Mic Example's sources can be downloaded as a ready-made Gradle project from [here](https://guides.micronaut.io/latest/micronaut-creating-first-graal-app-gradle-java.zip). Download, unzip and open the project in your IDE. -Before you proceed, make sure that you have Java on Truffle [installed](/reference-manual/java-on-truffle/#install-java-on-truffle) and set the GraalVM as the project SDK. +Before you proceed, make sure that you have Java on Truffle [installed](README.md#install-java-on-truffle) and set the GraalVM as the project SDK. ​ 1. In your IDE navigate to the root `build.gradle` within the sample project. Add: diff --git a/docs/reference-manual/java-on-truffle/ImplementationDetails.md b/docs/reference-manual/java-on-truffle/ImplementationDetails.md index 02b49e1b5ae7..866eb7486e3b 100644 --- a/docs/reference-manual/java-on-truffle/ImplementationDetails.md +++ b/docs/reference-manual/java-on-truffle/ImplementationDetails.md @@ -21,7 +21,7 @@ Java on Truffle is a minified Java VM that implements all core components of a V * Java Debug Wire Protocol (JDWP) Java on Truffle reuses all JARs and native libraries from GraalVM. -All native libraries and methods are loaded/accessed/called via [Truffle Native Function Interface (JNI)](https://www.graalvm.org/graalvm-as-a-platform/language-implementation-framework/NFI/). +All native libraries and methods are loaded/accessed/called via [Truffle Native Function Interface (JNI)](../../../truffle/docs/NFI.md). JNI handles are implemented in Java on Truffle, e.g., all Truffle NFI methods only receive and return primitives. Some methods are substituted for performance, e.g., `Math.sqrt`, `System.arraycopy`, avoiding the expensive transition to native. @@ -33,8 +33,8 @@ This mode is not used when running in a native image since there will be no conf * Java on Truffle does not implement the [JVM Tool Interface (JVMTI)](https://docs.oracle.com/en/java/javase/11/docs/specs/jvmti.html). As a result, it does not support the `-agentlib`, or `-agentpath` VM options. * Java on Truffle does not implement the `java.lang.instrument` interface. As a result it does not support the `-javaagent` VM option. -* Java on Truffle currently uses the standard native libraries from the Java core library. This requires allowing a polyglot `Context` native access. Because of the way these libraries are loaded (via [Truffle NFI](https://www.graalvm.org/graalvm-as-a-platform/language-implementation-framework/NFI/)), running on top of HotSpot only works on Linux (with `glibc`). Running as part of a native image works on Linux, Windows, and macOS but it currently limited to one context. +* Java on Truffle currently uses the standard native libraries from the Java core library. This requires allowing a polyglot `Context` native access. Because of the way these libraries are loaded (via [Truffle NFI](../../../truffle/docs/NFI.md)), running on top of HotSpot only works on Linux (with `glibc`). Running as part of a native image works on Linux, Windows, and macOS but it currently limited to one context. * Support for [Java Management Extensions (JMX)](https://docs.oracle.com/javase/tutorial/jmx/index.html) is partial and some methods might return partial data. -* The [Debugger Protocol Implementation (JDWP)](https://docs.oracle.com/javase/8/docs/technotes/guides/jpda/jdwp-spec.html) lacks some capabilities compared to HotSpot. It will correctly report the supported [capabilities](https://docs.oracle.com/javase/8/docs/platform/jpda/jdwp/jdwp-protocol.html#JDWP_VirtualMachine_Capabilities). In particular actions that require to enumerate all Java objects are not supported. However it does support a few hot reloading cases that HotSpot does not. See [Enhanced HotSwap Capabilities with Java on Truffle](/reference-manual/java-on-truffle/demos/#enhanced-hotswap-capabilities-with-java-on-truffle). +* The [Debugger Protocol Implementation (JDWP)](https://docs.oracle.com/javase/8/docs/technotes/guides/jpda/jdwp-spec.html) lacks some capabilities compared to HotSpot. It will correctly report the supported [capabilities](https://docs.oracle.com/javase/8/docs/platform/jpda/jdwp/jdwp-protocol.html#JDWP_VirtualMachine_Capabilities). In particular actions that require to enumerate all Java objects are not supported. However it does support a few hot reloading cases that HotSpot does not. See [Enhanced HotSwap Capabilities with Java on Truffle](Demos.md#enhanced-hotswap-capabilities-with-java-on-truffle). * When the `java.MultiThreaded` option is set to "false", [reference processing](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ref/package-summary.html) will not happen. Depending on the application, this could create resource leaks. Note that this option is set to "false" automatically if Java on Truffle runs in a context where a single-threaded language is enabled (e.g., JavaScript). -* Java on Truffle does not support the [Polyglot API](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/package-summary.html) yet. However, it provides a guest Java Polyglot API, described in `polyglot.jar`. For more information, see [Interoperability with Truffle Languages](/reference-manual/java-on-truffle/interoperability/). +* Java on Truffle does not support the [Polyglot API](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/package-summary.html) yet. However, it provides a guest Java Polyglot API, described in `polyglot.jar`. For more information, see [Interoperability with Truffle Languages](Interoperability.md). diff --git a/docs/reference-manual/java-on-truffle/Interoperability.md b/docs/reference-manual/java-on-truffle/Interoperability.md index 4c4e24b27587..19b1596af77b 100644 --- a/docs/reference-manual/java-on-truffle/Interoperability.md +++ b/docs/reference-manual/java-on-truffle/Interoperability.md @@ -7,7 +7,7 @@ permalink: /reference-manual/java-on-truffle/interoperability/ # Interoperability with Truffle Languages -Java on Truffle allows you to interface other "Truffle" languages (languages which interpreters are implemented with the [Truffle framework](/graalvm-as-a-platform/language-implementation-framework/)) to create polyglot programs -- programs written in more than one language. +Java on Truffle allows you to interface other "Truffle" languages (languages which interpreters are implemented with the [Truffle framework](../../../truffle/docs/README.md)) to create polyglot programs -- programs written in more than one language. This guide describes how to load code written in foreign languages, how to export and import objects between languages, how to use Java on Truffle objects from a foreign language, how to use foreign objects from Java on Truffle, and how to embed in host Java. @@ -21,7 +21,7 @@ How this type is attached to foreign objects is an implementation detail. ## Polyglot -Java on Truffle provides a guest Java Polyglot API, described in [`polyglot.jar`](#). +Java on Truffle provides a guest Java Polyglot API, described in `polyglot.jar`. This JAR is automatically injected on guest Java contexts but can be excluded with `--java.Polyglot=false`. You can import the `Polyglot` class to interact with other guest languages: diff --git a/docs/reference-manual/java-on-truffle/README.md b/docs/reference-manual/java-on-truffle/README.md index 6dfe6681fbc4..f240c2fcedd4 100644 --- a/docs/reference-manual/java-on-truffle/README.md +++ b/docs/reference-manual/java-on-truffle/README.md @@ -7,18 +7,18 @@ permalink: /reference-manual/java-on-truffle/ # Java on Truffle -Using GraalVM, you can run Java applications normally [on the JVM](/reference-manual/java/), in [Native Image](/reference-manual/native-image/), and now on Truffle. +Using GraalVM, you can run Java applications normally [on the JVM](../java/README.md), in [Native Image](../native-image/README.md), and now on Truffle. Java on Truffle is an implementation of the Java Virtual Machine Specification, [Java SE 8](https://docs.oracle.com/javase/specs/jvms/se8/html/index.html) and [Java SE 11](https://docs.oracle.com/javase/specs/jvms/se11/html/index.html), built upon GraalVM as a Truffle interpreter. It is a minified Java VM that includes all core components of a VM, implements the same API as the Java Runtime Environment library (libjvm.so), and reuses all JARs and native libraries from GraalVM. -See the [Implementation Details](/reference-manual/java-on-truffle/implementation/) for more information. +See the [Implementation Details](ImplementationDetails.md) for more information. The project name behind this implementation is "Espresso". Its open source version is available on [GitHub](https://github.com/oracle/graal/tree/master/espresso). -The Java on Truffle execution mode runs Java via a Java bytecode interpreter, implemented with the [Truffle framework](/graalvm-as-a-platform/language-implementation-framework/) – an open-source library for writing interpreters for programming languages. +The Java on Truffle execution mode runs Java via a Java bytecode interpreter, implemented with the [Truffle framework](../../../truffle/docs/README.md) – an open-source library for writing interpreters for programming languages. Now Java can be executed by the same principle as other languages in the GraalVM ecosystem (JavaScript, Ruby, Python, R), directly interoperate with those languages, and pass data back and forth in the same memory space. Besides complete language interoperability, with Java on Truffle you can: -- run Java bytecodes in a separate context from the host Java VM. It can run either a Java 8 or Java 11 guest or host JVM. In other words, you can embed a Java 8 context in a Java 11 application, by using [GraalVM’s Polyglot API](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/package-summary.html). +- run Java bytecodes in a separate context from the host Java VM. It can run either a Java 8, Java 11, Java 17 guest or host JVM. In other words, you can embed a Java 8 context in a Java 11 application, by using [GraalVM’s Polyglot API](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/package-summary.html). - leverage the whole stack of tools provided by the Truffle framework, not previously available for Java. - have an improved isolation of the host Java VM and the Java program running on Truffle, so you can run less trusted guest code. - run in the context of a native image while still allowing dynamically-loaded bytecodes. @@ -28,8 +28,8 @@ It is available as of version 21.0.0. ## Install Java on Truffle -To run Java on Truffle, you need to have [GraalVM installed](/docs/getting-started/#install-graalvm). -The Java on Truffle runtime is not available by default, but can be easily added to GraalVM using the [GraalVM Updater tool](/reference-manual/graalvm-updater/). +To run Java on Truffle, you need to have [GraalVM installed](../../getting-started/graalvm-community/get-started-graalvm-community.md). +The Java on Truffle runtime is not available by default, but can be easily added to GraalVM using the [GraalVM Updater tool](../graalvm-updater.md). For GraalVM Community Edition users, run the following command to install Java on Truffle from the GitHub catalog: ```shell @@ -81,7 +81,7 @@ You can still influence the performance by passing the following options to `jav * `--engine.MultiTier=true` to enable multi-tier compilation; * `--engine.Inlining=false` in combination with `--java.InlineFieldAccessors=true` to make the compilation faster, in exchange for slower performance. -The `--vm.XX:` syntax ensures the option is passed to the underlying [native image VM](https://www.graalvm.org/reference-manual/native-image/HostedvsRuntimeOptions). +The `--vm.XX:` syntax ensures the option is passed to the underlying [native image VM](../native-image/HostedvsRuntimeOptions.md). When using the `-XX:` syntax, the VM first checks if there is such an option in the Java on Truffle runtime. If there is none, it will try to apply this option to the underlying native image VM. This might be important for options such as `MaxDirectMemorySize` which can be set independently at both levels: `-XX:MaxDirectMemorySize=256M` controls how much native memory can be reserved by the Java program running on Truffle (the guest VM), while `--vm.XX:MaxDirectMemorySize=256M` controls how much native memory can be reserved by native image (the host VM). @@ -90,13 +90,13 @@ This might be important for options such as `MaxDirectMemorySize` which can be s #### From Command Line -For the purpose of this guide, GraalVM Enterprise 21.2.0 distribution, based on Java 11 for macOS, is used. +For the purpose of this guide, GraalVM Enterprise 21.3.0 distribution, based on Java 11 for macOS, is used. To ensure you have successfully installed Java on Truffle, verify its version: ```shell java -truffle -version -java version "11.0.12" 2021-07-20 LTS -Java(TM) SE Runtime Environment GraalVM EE 21.2.0 (build 11.0.12+8-LTS-jvmci-21.2-b06) -Espresso 64-Bit VM GraalVM EE 21.2.0 (build 11-espresso-21.2.0, mixed mode) +java version "11.0.13" 2021-10-19 LTS +Java(TM) SE Runtime Environment GraalVM EE 21.3.0 (build 11.0.13+9-LTS-jvmci-21.3-b03) +Espresso 64-Bit VM GraalVM EE 21.3.0 (build 11-espresso-21.3.0, mixed mode) ``` Taking this `HelloWorld.java` example, compile it and run from the command line: @@ -109,8 +109,8 @@ public class HelloWorld { ``` ```shell -/bin/javac HelloWorld.java -/bin/java -truffle HelloWorld +$JAVA_HOME/bin/javac HelloWorld.java +$JAVA_HOME/bin/java -truffle HelloWorld HelloWorld.java! ``` @@ -129,7 +129,7 @@ cd spring-petclinic 3. Then run it from the command line by selecting the `-truffle` runtime: ```java -java -truffle -jar target/spring-petclinic-2.4.2.jar +java -truffle -jar target/spring-petclinic--SNAPSHOT.jar ``` 4. When the application starts, access it on [localhost:8000](http://localhost:8080/). @@ -167,11 +167,11 @@ It should show GraalVM as project's JRE and VM options should include `-truffle ## What to Read Next Java on Truffle enables a seamless Java interoperability with other languages in the GraalVM ecosystem. -Check the [Interoperability with Truffle Languages guide](/reference-manual/java-on-truffle/interoperability/) to learn how to load code written in foreign languages, export and import objects between languages, how to use Java-on-Truffle objects from a foreign language and vice versa to create powerful polyglot programs. +Check the [Interoperability with Truffle Languages guide](Interoperability.md) to learn how to load code written in foreign languages, export and import objects between languages, how to use Java-on-Truffle objects from a foreign language and vice versa to create powerful polyglot programs. -To learn about the implementation approach, project's current status, and known limitations proceed to [Implementation Details](/reference-manual/java-on-truffle/implementation/). +To learn about the implementation approach, project's current status, and known limitations proceed to [Implementation Details](ImplementationDetails.md). You can already run some large applications like the Eclipse IDE, Scala or other languages REPLs, etc. in the Java on Truffle execution mode. -We recommend having a look at the collection of [Demo Applications](/reference-manual/java-on-truffle/demos/). +We recommend having a look at the collection of [Demo Applications](Demos.md). -If you have a question, check the available [FAQs](/reference-manual/java-on-truffle/faq/), or reach us directly over the **#espresso** channel in [GraalVM Slack](https://www.graalvm.org/slack-invitation/). +If you have a question, check the available [FAQs](FAQ.md), or reach us directly over the **#espresso** channel in [GraalVM Slack](https://www.graalvm.org/slack-invitation/). diff --git a/docs/reference-manual/java/Operations.md b/docs/reference-manual/java/Operations.md index d295a86b7e84..4c7d1c727655 100644 --- a/docs/reference-manual/java/Operations.md +++ b/docs/reference-manual/java/Operations.md @@ -9,75 +9,55 @@ permalink: /reference-manual/java/operations/ ## Running the GraalVM Compiler in Native Image vs on the JVM -When running the GraalVM compiler on the JVM, it goes through the same warm-up phase that the -rest of the Java application does. That is, it is first interpreted before -its hot methods are compiled. This can translate into slightly longer times -until the application reaches peak performance when compared to the native compilers -in the JVM such as C1 and C2. - -To address the issue of taking longer to reach to peak performance, **libgraal** -was introduced -- a shared library, produced using [Native Image](../native-image/README.md) to ahead-of-time compile the compiler itself. That means the GraalVM Enterprise -compiler is deployed as a native shared library. - -In this mode, the -compiler uses memory separate from the HotSpot heap, and it runs compiled from -the start. Therefore it has execution properties similar to other native HotSpot -compilers such as C1 and C2. Currently, this is the **default mode** of -operation. It can be disabled with `-XX:-UseJVMCINativeLibrary`. +When running the GraalVM compiler on the JVM, it goes through the same warm-up phase that the rest of the Java application does. +That is, it is first interpreted before its hot methods are compiled. +This can translate into slightly longer times until the application reaches peak performance when compared to the native compilers in the JVM such as C1 and C2. + +To address the issue of taking longer to reach to peak performance, **libgraal** was introduced -- a shared library, produced using [Native Image](../native-image/README.md) to ahead-of-time compile the compiler itself. +That means the GraalVM Enterprise compiler is deployed as a native shared library. + +In this mode, the compiler uses memory separate from the HotSpot heap, and it runs compiled from the start. +Therefore it has execution properties similar to other native HotSpot compilers such as C1 and C2. +Currently, this is the **default mode** of operation. +It can be disabled with `-XX:-UseJVMCINativeLibrary`. ## Measuring Performance The first thing to be sure of when measuring performance is to ensure the JVM is using the GraalVM Enterprise compiler. -In the GraalVM binary, the JVM is configured to use the GraalVM compiler -as the top tier compiler by default. You can confirm this by adding `-Dgraal.ShowConfiguration=info` -to the command line. It will produce a line of output similar to the one below -when the compiler is initialized: +In the GraalVM binary, the JVM is configured to use the GraalVM compiler as the top tier compiler by default. +You can confirm this by adding `-Dgraal.ShowConfiguration=info` to the command line. +It will produce a line of output similar to the one below when the compiler is initialized: ```shell Using Graal compiler configuration 'community' provided by org.graalvm.compiler.hotspot.CommunityCompilerConfigurationFactory loaded from jar:file:/Users/dsimon/graal/graal/compiler/mxbuild/dists/graal.jar!/org/graalvm/compiler/hotspot/CommunityCompilerConfigurationFactory.class ``` -Note: The GraalVM compiler is only initialized on the first top-tier JIT compilation request -so if your application is short-lived, you may not see this output. +> Note: The GraalVM compiler is only initialized on the first top-tier JIT compilation request so if your application is short-lived, you may not see this output. -Optimizing JVM-based applications is a science in itself. The compilation may not -even be a factor in the case of poor performance as the problem may -lie in any other part of the VM (I/O, garbage collection, threading, etc), or in -a poorly written application or 3rd party library code. For this reason, it's -worth utilizing the [JDK Mission Control](https://www.oracle.com/java/technologies/jdk-mission-control.html) tool chain to -diagnose the application behavior. +Optimizing JVM-based applications is a science in itself. +The compilation may not even be a factor in the case of poor performance as the problem may lie in any other part of the VM (I/O, garbage collection, threading, etc), or in +a poorly written application or 3rd party library code. For this reason, it is worth utilizing the [JDK Mission Control](https://www.oracle.com/java/technologies/jdk-mission-control.html) tool chain to diagnose the application behavior. -You can also compare performance against the native top-tier compiler in the JVM by -adding `-XX:-UseJVMCICompiler` to the command line. +You can also compare performance against the native top-tier compiler in the JVM by adding `-XX:-UseJVMCICompiler` to the command line. -If you observe a significant performance regression when using the GraalVM compiler, please -open an issue on GitHub. Attaching a Java Flight Recorder log and instructions -to reproduce the issue makes investigation easier and thus the -chances of a fix higher. Even better is if you can submit a [JMH](http://openjdk.java.net/projects/code-tools/jmh/) -benchmark that represents the hottest parts of your application (as identified -by a profiler). This allows us to very quickly pinpoint missing optimization -opportunities or to offer suggestions on how to restructure the code to -avoid or reduce performance bottlenecks. +If you observe a significant performance regression when using the GraalVM compiler, please open an issue on GitHub. +Attaching a Java Flight Recorder log and instructions to reproduce the issue makes investigation easier and thus the chances of a fix higher. +Even better is if you can submit a [JMH](http://openjdk.java.net/projects/code-tools/jmh/) benchmark that represents the hottest parts of your application (as identified by a profiler). +This allows us to very quickly pinpoint missing optimization opportunities or to offer suggestions on how to restructure the code to avoid or reduce performance bottlenecks. ## Troubleshooting the GraalVM Compiler -Like all software, the GraalVM compiler is not guaranteed to be bug free so it is useful to -know how to diagnose and submit useful bug reports if you encounter issues. +Like all software, the GraalVM compiler is not guaranteed to be bug free so it is useful to know how to diagnose and submit useful bug reports if you encounter issues. -If you spot a security vulnerability, please do **not** report it via GitHub Issues or the public mailing lists, -but via the process outlined at [Reporting Vulnerabilities guide](https://www.oracle.com/corporate/security-practices/assurance/vulnerability/reporting.html). +If you spot a security vulnerability, please do **not** report it via GitHub Issues or the public mailing lists, but via the process outlined at [Reporting Vulnerabilities guide](https://www.oracle.com/corporate/security-practices/assurance/vulnerability/reporting.html). ### Compilation Exceptions -One advantage of the compiler being written in Java is that runtime exceptions during -compilation are not fatal VM errors. Instead, each compilation has an exception -handler that takes action based on the `graal.CompilationFailureAction` -property. +One advantage of the compiler being written in Java is that runtime exceptions during compilation are not fatal VM errors. +Instead, each compilation has an exception handler that takes action based on the `graal.CompilationFailureAction` property. -The default value is `Silent`. Specifying `Diagnose` causes failing compilations to be retried -with extra diagnostics enabled. In this case, just before the VM exits, all diagnostic output -captured during retried compilations is written to a `.zip` file and its location -is printed on the console: +The default value is `Silent`. Specifying `Diagnose` causes failing compilations to be retried with extra diagnostics enabled. +In this case, just before the VM exits, all diagnostic output captured during retried compilations is written to a `.zip` file and its location is printed on the console: ```shell Graal diagnostic output saved in /Users/demo/graal-dumps/1499768882600/graal_diagnostics_64565.zip ``` @@ -92,11 +72,8 @@ are also supported: ### Code Generation Errors The other type of error you might encounter with compilers is the production of incorrect machine code. -This error can cause a VM crash, which should produce a file that starts with -`hs_err_pid` in the current working directory of the VM process. In most cases, -there is a section in the file that shows the stack at the time of the crash, -including the type of code for each frame in the stack, as in the following -example: +This error can cause a VM crash, which should produce a file that starts with `hs_err_pid` in the current working directory of the VM process. +In most cases, there is a section in the file that shows the stack at the time of the crash, including the type of code for each frame in the stack, as in the following example: ```shell Stack: [0x00007000020b1000,0x00007000021b1000], sp=0x00007000021af7a0, free space=1017k @@ -106,16 +83,14 @@ j org.graalvm.compiler.core.gen.NodeLIRBuilder.doBlock(Lorg/graalvm/compiler/no j org.graalvm.compiler.core.LIRGenerationPhase.emitBlock(Lorg/graalvm/compiler/nodes/spi/NodeLIRBuilderTool;Lorg/graalvm/compiler/lir/gen/LIRGenerationResult;Lorg/graalvm/compiler/nodes/cfg/Block;Lorg/graalvm/compiler/nodes/StructuredGraph;Lorg/graalvm/compiler/core/common/cfg/BlockMap;)V+65 ``` -This example shows that the top frame was compiled (J) by the JVMCI compiler, -which is the GraalVM compiler. The crash occurred at offset 0x141 in the machine -code produced for: +This example shows that the top frame was compiled (J) by the JVMCI compiler, which is the GraalVM compiler. +The crash occurred at offset 0x141 in the machine code produced for: ```shell org.graalvm.compiler.core.gen.NodeLIRBuilder.matchComplexExpressions(Ljava/util/List;)V ``` -The next two frames in the stack were executed in the interpreter (j). The -location of the crash is also often indicated near the top of the file with -something like this: +The next two frames in the stack were executed in the interpreter (`j`). +The location of the crash is also often indicated near the top of the file with something like this: ```shell # Problematic frame: # J 761 JVMCI org.graalvm.compiler.core.gen.NodeLIRBuilder.matchComplexExpressions(Ljava/util/List;)V (299 bytes) @ 0x0000000108a2fc01 [0x0000000108a2fac0+0x141] (null) @@ -123,30 +98,22 @@ something like this: In this example, there is likely an error in the code produced by the GraalVM compiler for `NodeLIRBuilder.matchComplexExpressions`. -When filing an issue on [GitHub](https://github.com/oracle/graal/issues) -for such a crash, you should first attempt to reproduce the crash with extra -diagnostics enabled for the compilation of the problematic method. +When filing an issue on [GitHub](https://github.com/oracle/graal/issues) for such a crash, you should first attempt to reproduce the crash with extra diagnostics enabled for the compilation of the problematic method. In this example, you would add the following to your command line: ```shell -Dgraal.MethodFilter=NodeLIRBuilder.matchComplexExpressions, -Dgraal.Dump=:2 ``` These options are described in more detail [here](https://github.com/oracle/graal/blob/master/compiler/docs/Debugging.md). -In brief, these options tell the compiler to capture snapshots of the compiler state at -verbosity level 2 while compiling any method named `matchComplexExpressions` in -a class with a simple name of `NodeLIRBuilder`. The complete format of the -`MethodFilter` option is described in the output of `java -XX:+JVMCIPrintProperties`. +In brief, these options tell the compiler to capture snapshots of the compiler state at verbosity level 2 while compiling any method named `matchComplexExpressions` in a class with a simple name of `NodeLIRBuilder`. +The complete format of the `MethodFilter` option is described in the output of `java -XX:+JVMCIPrintProperties`. -Quite often, the crash location does not exist directly in the problematic method -mentioned in the crash log but comes from an inlined method. +Quite often, the crash location does not exist directly in the problematic method mentioned in the crash log but comes from an inlined method. -In such a case, simply filtering for the problematic method might not capture an -erroneous compilation causing a crash. +In such a case, simply filtering for the problematic method might not capture an erroneous compilation causing a crash. -To improve the likelihood of capturing an erroneous compilation, you need to -broaden the `MethodFilter` value. To guide this, add `-Dgraal.PrintCompilation=true` -when trying to reproduce the crash so you can see what was compiled just before -the crash. +To improve the likelihood of capturing an erroneous compilation, you need to broaden the `MethodFilter` value. +To guide this, add `-Dgraal.PrintCompilation=true` when trying to reproduce the crash so you can see what was compiled just before the crash. The following shows sample output from the console: ```shell @@ -166,19 +133,15 @@ HotSpotCompilation-1221 Lorg/graalvm/compiler/hotspot/amd64/AMD64HotSpotL # Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again ``` Here we see that the crash happened in a different method than the first crash. -As such, we expand the filter argument to be `-Dgraal.MethodFilter= -NodeLIRBuilder.matchComplexExpressions,AMD64HotSpotLIRGenerator.getResult` -and run again. +As such, we expand the filter argument to be `-Dgraal.MethodFilter=NodeLIRBuilder.matchComplexExpressions,AMD64HotSpotLIRGenerator.getResult` and run again. -When the VM crashes in this way, it does not execute the shutdown code that -archives the GraalVM compiler diagnostic output or delete the directory it was written to. +When the VM crashes in this way, it does not execute the shutdown code that archives the GraalVM compiler diagnostic output or delete the directory it was written to. This must be done manually after the crash. By default, the directory is `$PWD/graal-dumps/`; for example, `./graal-dumps/1499938817387`. However, you can set the directory with `-Dgraal.DumpPath=`. -A message, such as the following, is printed to the console when this -directory is first used by the compiler: +A message, such as the following, is printed to the console when this directory is first used by the compiler: ```shell Dumping debug output in /Users/demo/graal-dumps/1499768882600 ``` diff --git a/docs/reference-manual/java/Options.md b/docs/reference-manual/java/Options.md index bae8f2e4eb38..e9bfc3744a2a 100644 --- a/docs/reference-manual/java/Options.md +++ b/docs/reference-manual/java/Options.md @@ -133,4 +133,4 @@ Becomes: js --jvm --vm.Dgraal.ShowConfiguration=info -version ``` -Note the `-D` prefix is replaced by `--vm.D`. +> Note the `-D` prefix is replaced by `--vm.D`. diff --git a/docs/reference-manual/java/README.md b/docs/reference-manual/java/README.md index 6dac35785069..ce9337c9355f 100644 --- a/docs/reference-manual/java/README.md +++ b/docs/reference-manual/java/README.md @@ -14,7 +14,7 @@ The JVM passes bytecode to the GraalVM compiler, which compiles that to the mach GraalVM's dynamic compiler can improve the efficiency and the speed of applications written in Java, Scala, Kotlin, or other JVM languages through unique approaches to code analysis and optimization. For example, it assures performance advantages for highly abstracted programs due to its ability to remove costly object allocations. -To learn more, go to the [Compiler](/reference-manual/compiler/) page. +To learn more, go to the [Compiler](../compiler.md) page. The open source compiler's code is available on [GitHub](https://github.com/oracle/graal/tree/master/compiler). ## Compiler Operating Modes @@ -28,10 +28,10 @@ This is the default and recommended mode of operation. - **jargraal**: the GraalVM compiler goes through the same warm-up phase that the rest of the Java application does. That is, it is first interpreted before its hot methods are compiled. This mode is selected with the `-XX:-UseJVMCINativeLibrary` command-line option. This will delay the time to reach peak performance as the compiler itself needs to be compiled before it produces code quickly. -This mode allows you to [debug the GraalVM compiler with a Java debugger](Operations.md/#troubleshooting-the-graalvm-compiler). +This mode allows you to [debug the GraalVM compiler with a Java debugger](Operations.md#troubleshooting-the-graalvm-compiler). ## Interoperability -In addition to running JVM-based languages on GraalVM, you can also call any other language implemented with the [Truffle language implementation framework](../truffle-framework/README.md) directly from Java. -See the [Polyglot Programming](../polyglot-programming.md) and [Embedding Languages](../embed-languages.md) guides for more information about interoperability with other programming languages. +In addition to running JVM-based languages on GraalVM, you can also call any other language implemented with the [Truffle language implementation framework](../../../truffle/docs/README.md) directly from Java. +See the [Polyglot Programming](../polyglot-programming.md) and [Embedding Languages](../embedding/embed-languages.md) guides for more information about interoperability with other programming languages. diff --git a/docs/reference-manual/languages.md b/docs/reference-manual/languages.md index 061c9f85a505..9354047ae4b3 100644 --- a/docs/reference-manual/languages.md +++ b/docs/reference-manual/languages.md @@ -13,9 +13,9 @@ GraalVM's polyglot capabilities make it possible to mix multiple programming lan If you are mostly interested in GraalVM's support for a specific language, here you can find the most extensive documentation: * [Java](java/README.md) * [Java on Truffle](java-on-truffle/README.md) -* [JavaScript and Node.js](js/README.md) +* [JavaScript and Node.js](https://github.com/oracle/graaljs/blob/master/docs/user/README.md) * [LLVM Languages](llvm/README.md) -* [Python](python/README.md) -* [R](r/README.md) -* [Ruby](ruby/README.md) +* [Python](https://github.com/oracle/graalpython/blob/master/docs/user/README.md) +* [R](https://github.com/oracle/fastr/blob/master/documentation/user/README.md) +* [Ruby](https://github.com/oracle/truffleruby/blob/master/doc/user/README.md) * [WebAssembly](wasm/README.md) diff --git a/docs/reference-manual/llvm/Compatibility.md b/docs/reference-manual/llvm/Compatibility.md index 7f285f5a1331..c2925c1ea2a3 100644 --- a/docs/reference-manual/llvm/Compatibility.md +++ b/docs/reference-manual/llvm/Compatibility.md @@ -11,21 +11,15 @@ It is recommended to use the LLVM toolchain shipped with GraalVM. ## Optimizations Flags -In contrast to the static compilation model of LLVM languages, in GraalVM the -machine code is not directly produced from the LLVM bitcode. There is an -additional dynamic compilation step by the GraalVM compiler. +In contrast to the static compilation model of LLVM languages, in GraalVM the machine code is not directly produced from the LLVM bitcode. +There is an additional dynamic compilation step by the GraalVM compiler. -First, the LLVM frontend (e.g., `clang`) performs optimizations on -the bitcode level, and then the GraalVM compiler does its own optimizations on top of that -during dynamic compilation. Some optimizations are better when done -ahead-of-time on bitcode, while other optimizations are better left for the -dynamic compilation of the GraalVM compiler, when profiling information is available. +First, the LLVM frontend (e.g., `clang`) performs optimizations on the bitcode level, and then the GraalVM compiler does its own optimizations on top of that during dynamic compilation. +Some optimizations are better when done ahead-of-time on bitcode, while other optimizations are better left for the dynamic compilation of the GraalVM compiler, when profiling information is available. -The LLVM toolchain that is shipped with GraalVM automatically selects the -recommended flags by default. +The LLVM toolchain that is shipped with GraalVM automatically selects the recommended flags by default. -Generally, all optimization levels should work, but for a better result, it is -recommended to compile the bitcode with the optimization level `-O1`. +Generally, all optimization levels should work, but for a better result, it is recommended to compile the bitcode with the optimization level `-O1`. For cross-language interoperability, the `-mem2reg` optimization is required. There are two ways to get that: either compile with at least `-O1`, or use the `opt` tool to apply the `-mem2reg` optimization manually. diff --git a/docs/reference-manual/llvm/Compiling.md b/docs/reference-manual/llvm/Compiling.md index 4c7d74b507b1..494d8fb74c41 100644 --- a/docs/reference-manual/llvm/Compiling.md +++ b/docs/reference-manual/llvm/Compiling.md @@ -11,8 +11,7 @@ As the first step, you have to compile a program to LLVM bitcode using some LLVM ## File Format -While the GraalVM LLVM runtime can execute [plain bitcode files](https://llvm.org/docs/BitCodeFormat.html), -the preferred format is a _native executable_ with _embedded bitcode_. +While the GraalVM LLVM runtime can execute [plain bitcode files](https://llvm.org/docs/BitCodeFormat.html), the preferred format is a _native executable_ with _embedded bitcode_. The executable file formats differ on Linux and macOS. Linux by default uses ELF files. The bitcode is stored in a section called `.llvmbc`. @@ -31,17 +30,17 @@ To simplify compiling C/C++ to executables with embedded bitcode, GraalVM comes The toolchain contains compilers such as `clang` for C or `clang++` for C++, but also other tools that are needed for building native projects such as a linker (`ld`), or an archiver (`ar`) for creating static libraries. -The LLVM toolchain can be added to GraalVM on demand with the [GraalVM Updater](https://www.graalvm.org/reference-manual/graalvm-updater) tool: +The LLVM toolchain can be added to GraalVM on demand with the [GraalVM Updater](../graalvm-updater.md) tool: ```shell $GRAALVM_HOME/bin/gu install llvm-toolchain ``` The above command will install the LLVM toolchain from the GitHub catalog for GraalVM Community users. -For GraalVM Enterprise users, the [manual installation](https://www.graalvm.org/reference-manual/graalvm-updater/#manual-installation) is required. +For GraalVM Enterprise users, the [manual installation](../graalvm-updater.md#manual-installation) is required. To get the location of the toolchain, use the `--print-toolchain-path` argument of `lli`: ```shell -export LLVM_TOOLCHAIN=$($GRAALVM_HOME/bin/lli --print-toolchain-path) +export LLVM_TOOLCHAIN=$($JAVA_HOME/bin/lli --print-toolchain-path) ``` See the content of the toolchain path for a list of available tools: @@ -66,13 +65,13 @@ $LLVM_TOOLCHAIN/clang hello.c -o hello The resulting executable, `hello`, can be executed on GraalVM using `lli`: ```shell -$GRAALVM_HOME/bin/lli hello +$JAVA_HOME/bin/lli hello ``` ## External Library Dependencies -If the bitcode file depends on external libraries, GraalVM will automatically -pick up the dependencies from the binary headers. For example: +If the bitcode file depends on external libraries, GraalVM will automatically pick up the dependencies from the binary headers. +For example: ```c #include #include @@ -95,9 +94,9 @@ lli hello-curses ## Running C++ -For running C++ code, the GraalVM LLVM runtime requires the -[`libc++`](https://libcxx.llvm.org) standard library from the LLVM project. The -LLVM toolchain shipped with GraalVM automatically links against `libc++`. For example, save this code as a _hello-c++.cpp_ file: +For running C++ code, the GraalVM LLVM runtime requires the [`libc++`](https://libcxx.llvm.org) standard library from the LLVM project. +The LLVM toolchain shipped with GraalVM automatically links against `libc++`. +For example, save this code as a _hello-c++.cpp_ file: ```c++ #include @@ -115,9 +114,8 @@ Hello, C++ World! ## Running Rust -The LLVM toolchain, bundled with GraalVM, does not come with the Rust -compiler. To install Rust, run the following in your command prompt, then follow the -onscreen instructions: +The LLVM toolchain, bundled with GraalVM, does not come with the Rust compiler. +To install Rust, run the following in your command prompt, then follow the onscreen instructions: ```shell curl https://sh.rustup.rs -sSf | sh ``` @@ -134,32 +132,26 @@ This can be then compiled to bitcode with the `--emit=llvm-bc` flag: rustc --emit=llvm-bc hello-rust.rs ``` -To run the Rust program, we have to tell GraalVM where to find the Rust -standard libraries: +To run the Rust program, we have to tell GraalVM where to find the Rust standard libraries: ```shell lli --lib $(rustc --print sysroot)/lib/libstd-* hello-rust.bc Hello Rust! ``` -Since the Rust compiler is not using the LLVM toolchain shipped with GraalVM, depending on the -local Rust installation, an error similar to one of the following might happen: +Since the Rust compiler is not using the LLVM toolchain shipped with GraalVM, depending on the local Rust installation, an error similar to one of the following might happen: ``` Mismatching target triple (expected x86_64-unknown-linux-gnu, got x86_64-pc-linux-gnu) Mismatching target triple (expected x86_64-apple-macosx10.11.0, got x86_64-apple-darwin) ``` -This indicates that the Rust compiler used a different target triple than the LLVM toolchain -shipped with GraalVM. In this particular case, the differences are just different naming -conventions across Linux distributions or MacOS versions, there is no real difference. +This indicates that the Rust compiler used a different target triple than the LLVM toolchain shipped with GraalVM. +In this particular case, the differences are just different naming conventions across Linux distributions or MacOS versions, there is no real difference. In that case, the error can be safely ignored: ```shell lli --experimental-options --llvm.verifyBitcode=false --lib $(rustc --print sysroot)/lib/libstd-* hello-rust.bc ``` -This option should only be used after manually verifying that the target triples are -really compatible, i.e., the architecture, operating system, and C library all match. -For example, `x86_64-unknown-linux-musl` and `x86_64-unknown-linux-gnu` are really different, -the bitcode is compiled for a different C library. The `--llvm.verifyBitcode=false` option -disables all checks, GraalVM will then try to run the bitcode regardless, which might randomly -fail in unexpected ways. +This option should only be used after manually verifying that the target triples are really compatible, i.e., the architecture, operating system, and C library all match. +For example, `x86_64-unknown-linux-musl` and `x86_64-unknown-linux-gnu` are really different, the bitcode is compiled for a different C library. +The `--llvm.verifyBitcode=false` option disables all checks, GraalVM will then try to run the bitcode regardless, which might randomly fail in unexpected ways. diff --git a/docs/reference-manual/llvm/Debugging.md b/docs/reference-manual/llvm/Debugging.md index 6cd9556f5273..fe8700e131b7 100644 --- a/docs/reference-manual/llvm/Debugging.md +++ b/docs/reference-manual/llvm/Debugging.md @@ -12,13 +12,9 @@ This includes support for single-stepping, breakpoints, and inspection of local To use this feature, make sure to compile your program with debug information enabled by specifying the `-g` argument when compiling with `clang` (the LLVM toolchain shipped with GraalVM will automatically enable debug information). This gives you the ability to step through the program's source code and set breakpoints in it. -With GraalVM 20.0 and older, the option `--llvm.enableLVI=true` is needed for being able to inspect variables during debugging. -This option is not enabled by default as it decreases the program's run-time performance. -Starting with GraalVM 20.1, this option is not needed anymore and thus deprecated. - To start debugging, run `lli` with the `--inspect` option: ```shell -$GRAALVM_HOME/bin/lli --inspect +$JAVA_HOME/bin/lli --inspect ``` When launched, the inspector will suspend execution at the first instruction of the program and print a link to the console. @@ -35,14 +31,13 @@ To instead parse functions eagerly, and be able to set breakpoints also in funct Program-defined breakpoints using the `__builtin_debugtrap` function enables you to mark locations in the program at which you explicitly want GraalVM to halt the program and switch to the debugger. The debugger automatically halts at each call to this function as if a breakpoint were set on the call. You can use this feature to quickly reach the code you are actually trying to debug without having to first find and set a breakpoint on it after launching your application. -You can also instruct Chrome Inspector not to suspend your program at the first source-level statement being executed. When doing so, GraalVM will instead execute your program until it reaches a call to `__builtin_debugtrap()` before invoking the debugger. +You can also instruct Chrome Inspector not to suspend your program at the first source-level statement being executed. +When doing so, GraalVM will instead execute your program until it reaches a call to `__builtin_debugtrap()` before invoking the debugger. To enable this behavior you need to pass the arguments `lli --inspect.Suspend=false --inspect.WaitAttached=true`. ## Locating Source Files -Debug information in LLVM bitcode files contains absolute search paths to identify the -location of source code. If the source files did not move, it should be found automatically. +Debug information in LLVM bitcode files contains absolute search paths to identify the location of source code. +If the source files did not move, it should be found automatically. -If the source files moved, or were compiled on a different machine, a search path can be -specified using the `--inspect.SourcePath=` option (multiple paths can be separated -by `:`). +If the source files moved, or were compiled on a different machine, a search path can be specified using the `--inspect.SourcePath=` option (multiple paths can be separated by `:`). diff --git a/docs/reference-manual/llvm/Interoperability.md b/docs/reference-manual/llvm/Interoperability.md index 7910a0e0b877..9900f825bba0 100644 --- a/docs/reference-manual/llvm/Interoperability.md +++ b/docs/reference-manual/llvm/Interoperability.md @@ -9,13 +9,10 @@ permalink: /reference-manual/llvm/Interoperability/ GraalVM supports several other programming languages including JavaScript, Python, Ruby, and R. While GraalVM's implementation of `lli` is designed to run LLVM bitcode, it also provides the API for programming language interoperability that lets you execute code from any other GraalVM-supported language. -Dynamic languages like JavaScript usually access object members by name. Since -normally names are not preserved in LLVM bitcode, it must be compiled with debug -information enabled (the LLVM toolchain shipped with GraalVM will automatically enable -debugging information). +Dynamic languages like JavaScript usually access object members by name. +Since normally names are not preserved in LLVM bitcode, it must be compiled with debug information enabled (the LLVM toolchain shipped with GraalVM will automatically enable debugging information). -The following example demonstrates how you can use the API for interoperability -with other programming languages. +The following example demonstrates how you can use the API for interoperability with other programming languages. Define a C struct for points and implement allocation functions in a file named _cpart.c_: @@ -52,9 +49,7 @@ void printPoint(struct Point *p) { } ``` -Make sure `LLVM_TOOLCHAIN` resolves to the GraalVM LLVM toolchain (`lli --print-toolchain-path`), -and then compile _cpart.c_ (the graalvm-llvm library defines the polyglot -API functions used in the example): +Make sure `LLVM_TOOLCHAIN` resolves to the GraalVM LLVM toolchain (`lli --print-toolchain-path`), and then compile _cpart.c_ (the graalvm-llvm library defines the Polyglot API functions used in the example): ```shell $LLVM_TOOLCHAIN/clang -shared cpart.c -lgraalvm-llvm -o cpart.so ``` @@ -104,9 +99,8 @@ Point<17.000000,42.000000> ## Polyglot C API -There are also lower level API functions for directly accessing polyglot values -from C. See the [Polyglot Programming](https://graalvm.org/reference-manual/polyglot-programming/) reference -and the comments in `polyglot.h` for more details. +There are also lower level API functions for directly accessing polyglot values from C. +See the [Polyglot Programming](../polyglot-programming.md) reference and the comments in `polyglot.h` for more details. For example, this program allocates and accesses a Java array from C: ```c @@ -163,5 +157,4 @@ java Polyglot 24 ``` -See the [Embedding Languages](https://graalvm.org/reference-manual/embed-languages/) reference for -more information. +See the [Embedding Languages](../embedding/embed-languages.md) reference for more information. diff --git a/docs/reference-manual/llvm/NativeExecution.md b/docs/reference-manual/llvm/NativeExecution.md index 6171d928ffc6..6892db89e2f7 100644 --- a/docs/reference-manual/llvm/NativeExecution.md +++ b/docs/reference-manual/llvm/NativeExecution.md @@ -12,24 +12,16 @@ The difference lies in safety guarantees and cross-language interoperability. Note: Managed execution mode for LLVM bitcode is possible with GraalVM Enterprise only. -In the default configuration, cross-language interoperability requires bitcode -to be compiled with the debug information enabled (`-g`), and the `-mem2reg` -optimization performed on LLVM bitcode (compiled with at least `-O1`, or -explicitly using the `opt` tool). These requirements can be overcome in a -managed environment of GraalVM Enterprise that allows native code to participate in the -polyglot programs, passing and receiving the data from any other supported -language. In terms of security, the execution of native code in a managed -environment passes with additional safety features: catching illegal pointer -accesses, accessing arrays outside of the bounds, etc. +In the default configuration, cross-language interoperability requires bitcode to be compiled with the debug information enabled (`-g`), and the `-mem2reg` optimization performed on LLVM bitcode (compiled with at least `-O1`, or explicitly using the `opt` tool). +These requirements can be overcome in a managed environment of GraalVM Enterprise that allows native code to participate in the polyglot programs, passing and receiving the data from any other supported language. +In terms of security, the execution of native code in a managed environment passes with additional safety features: catching illegal pointer accesses, accessing arrays outside of the bounds, etc. There are certain limitations and differences to the native execution depending on the GraalVM edition. Consider them respectively. ### Limitations and Differences to Native Execution on Top of GraalVM Community -The LLVM interpreter in GraalVM Community Edition environment allows executing LLVM bitcode within a -multilingual context. Even though it aspires to be a generic LLVM runtime, there -are certain fundamental and/or implementational limitations that users need to -be aware of. +The LLVM interpreter in GraalVM Community Edition environment allows executing LLVM bitcode within a multilingual context. +Even though it aspires to be a generic LLVM runtime, there are certain fundamental and/or implementational limitations that users need to be aware of. The following restrictions and differences to native execution (i.e., bitcode compiled down to native code) exist when LLVM bitcode is executed with the LLVM interpreter on top of GraalVM Community: diff --git a/docs/reference-manual/llvm/README.md b/docs/reference-manual/llvm/README.md index dfcd66c93ff0..829b9d8c943c 100644 --- a/docs/reference-manual/llvm/README.md +++ b/docs/reference-manual/llvm/README.md @@ -14,15 +14,16 @@ This allows seamless interoperability with the dynamic languages supported by Gr ## Running LLVM Bitcode on GraalVM -To run LLVM-based languages on GraalVM, the binaries need to be compiled with embedded -bitcode. The [Compiling](Compiling.md) guide provides information on -how to compile a program to LLVM bitcode and what file format is expected. +To run LLVM-based languages on GraalVM, the binaries need to be compiled with embedded bitcode. +The [Compiling](Compiling.md) guide provides information on how to compile a program to LLVM bitcode and what file format is expected. The syntax to execute programs in LLVM bitcode format on GraalVM is: ```shell lli [LLI options] [GraalVM options] [polyglot options] [program args] ``` -Here, `` is [a compiled program with embedded LLVM bitcode](Compiling.md). See [LLI Command Options](Options.md) or use `lli --help` for options explanations. -Note: LLVM bitcode is platform-dependent. The program must be compiled to -bitcode for an appropriate platform. +Here, `` is [a compiled program with embedded LLVM bitcode](Compiling.md). +See [LLI Command Options](Options.md) or use `lli --help` for options explanations. + +Note: LLVM bitcode is platform-dependent. +The program must be compiled to bitcode for an appropriate platform. diff --git a/docs/reference-manual/native-image/Agent.md b/docs/reference-manual/native-image/Agent.md index 1505c516379d..bfbf7d51c920 100644 --- a/docs/reference-manual/native-image/Agent.md +++ b/docs/reference-manual/native-image/Agent.md @@ -72,11 +72,9 @@ public class ReflectionExample { } ``` -This is a simple Java program where non-constant strings for accessing program -elements by name must come as external inputs. The main method invokes a method -of a particular class (`Class.forName`) whose names are passed as command line -arguments. Providing any other class or method name on the command line leads to -an exception. +This is a simple Java program where non-constant strings for accessing program elements by name must come as external inputs. +The main method invokes a method of a particular class (`Class.forName`) whose names are passed as command line arguments. +Providing any other class or method name on the command line leads to an exception. Having compiled the example, invoke each method: ```shell @@ -94,10 +92,7 @@ $JAVA_HOME/bin/native-image ReflectionExample ... ./reflectionexample ``` -The `reflectionexample` binary is just a launcher for the JVM. To -build a native image with reflective lookup operations, apply the tracing -agent to write a configuration file to be later fed into the native image -build together. +The `reflectionexample` binary is just a launcher for the JVM. To build a native image with reflective lookup operations, apply the tracing agent to write a configuration file to be later fed into the native image build together. 1. Create a directory `META-INF/native-image` in the working directory: ```shell @@ -108,17 +103,16 @@ mkdir -p META-INF/native-image ```shell $JAVA_HOME/bin/java -agentlib:native-image-agent=config-output-dir=META-INF/native-image ReflectionExample StringReverser reverse "hello" ``` -This command creates a _reflection-config.json_ file which makes the `StringReverser` class and the `reverse()` method accessible via reflection. The _jni-config.json_, _proxy-config.json_ , and _resource-config.json_ configuration files are written in that directory too. +This command creates a _reflection-config.json_ file which makes the `StringReverser` class and the `reverse()` method accessible via reflection. +The _jni-config.json_, _proxy-config.json_ , and _resource-config.json_ configuration files are written in that directory too. 3. Build a native image: ```shell $JAVA_HOME/bin/native-image --no-fallback ReflectionExample ``` -The native image builder automatically picks up configuration files in the -_META-INF/native-image_ directory or subdirectories. However, it is recommended -to have _META-INF/native-image_ location on the class path, either via a JAR -file or via the `-cp` flag. It will help to avoid confusion for IDE users where a -directory structure is defined by the tool. +The native image builder automatically picks up configuration files in the _META-INF/native-image_ directory or subdirectories. +However, it is recommended to have _META-INF/native-image_ location on the class path, either via a JAR file or via the `-cp` flag. +It will help to avoid confusion for IDE users where a directory structure is defined by the tool. 4. Test the methods, but remember that you have not run the tracing agent twice to create a configuration that supports both: ```shell @@ -131,20 +125,15 @@ Exception in thread "main" java.lang.ClassNotFoundException: StringCapitalizer at ReflectionExample.main(ReflectionExample.java:21) ``` -Neither the tracing agent nor native images generator can automatically check -if the provided configuration files are complete. The agent only observes and -records which values are accessed through reflection so that the same accesses -are possible in a native image. You can either manually edit the -_reflection-config.json_ file, or re-run the tracing agent to transform the -existing configuration file, or extend it by using `config-merge-dir` option: +Neither the tracing agent nor native images generator can automatically check if the provided configuration files are complete. +The agent only observes and records which values are accessed through reflection so that the same accesses are possible in a native image. +You can either manually edit the _reflection-config.json_ file, or re-run the tracing agent to transform the existing configuration file, or extend it by using `config-merge-dir` option: ```shell $JAVA_HOME/bin/java -agentlib:native-image-agent=config-merge-dir=META-INF/native-image ReflectionExample StringCapitalizer capitalize "hello" ``` -Note, the different `config-merge-dir` option instructs the agent to extend the -existing configuration files instead of overwriting them. After re-building the -native image, the `StringCapitalizer` class and the `capitalize` method will be -accessible too. +Note, the different `config-merge-dir` option instructs the agent to extend the existing configuration files instead of overwriting them. +After re-building the native image, the `StringCapitalizer` class and the `capitalize` method will be accessible too. ![](/img/reflect_config_file_merged.png) @@ -152,9 +141,13 @@ accessible too. ### Caller-based Filters -By default, the agent filters dynamic accesses which Native Image supports without configuration. The filter mechanism works by identifying the Java method performing the access, also referred to as _caller_ method, and matching its declaring class against a sequence of filter rules. The built-in filter rules exclude dynamic accesses which originate in the JVM, or in parts of a Java class library directly supported by Native Image (such as `java.nio`) from the generated configuration files. Which item (class, method, field, resource, etc.) is being accessed is not relevant for filtering. +By default, the agent filters dynamic accesses which Native Image supports without configuration. +The filter mechanism works by identifying the Java method performing the access, also referred to as _caller_ method, and matching its declaring class against a sequence of filter rules. +The built-in filter rules exclude dynamic accesses which originate in the JVM, or in parts of a Java class library directly supported by Native Image (such as `java.nio`) from the generated configuration files. +Which item (class, method, field, resource, etc.) is being accessed is not relevant for filtering. -In addition to the built-in filter, custom filter files with additional rules can be specified using the `caller-filter-file` option. For example: `-agentlib:caller-filter-file=/path/to/filter-file,config-output-dir=...` +In addition to the built-in filter, custom filter files with additional rules can be specified using the `caller-filter-file` option. +For example: `-agentlib:caller-filter-file=/path/to/filter-file,config-output-dir=...` Filter files have the following structure: ```json @@ -166,25 +159,46 @@ Filter files have the following structure: } ``` -The `rules` section contains a sequence of rules. Each rule specifies either `includeClasses`, which means that lookups originating in matching classes will be included in the resulting configuration, or `excludeClasses`, which excludes lookups originating in matching classes from the configuration. Each rule defines a pattern for the set of matching classes, which can end in `.*` or `.**`: a `.*` ending matches all classes in a package and that package only, while a `.**` ending matches all classes in the package as well as in all subpackages at any depth. Without `.*` or `.**`, the rule applies only to a single class with the qualified name that matches the pattern. All rules are processed in the sequence in which they are specified, so later rules can partially or entirely override earlier ones. When multiple filter files are provided (by specifying multiple `caller-filter-file` options), their rules are chained together in the order in which the files are specified. The rules of the built-in caller filter are always processed first, so they can be overridden in custom filter files. +The `rules` section contains a sequence of rules. +Each rule specifies either `includeClasses`, which means that lookups originating in matching classes will be included in the resulting configuration, or `excludeClasses`, which excludes lookups originating in matching classes from the configuration. +Each rule defines a pattern for the set of matching classes, which can end in `.*` or `.**`: a `.*` ending matches all classes in a package and that package only, while a `.**` ending matches all classes in the package as well as in all subpackages at any depth. Without `.*` or `.**`, the rule applies only to a single class with the qualified name that matches the pattern. +All rules are processed in the sequence in which they are specified, so later rules can partially or entirely override earlier ones. +When multiple filter files are provided (by specifying multiple `caller-filter-file` options), their rules are chained together in the order in which the files are specified. +The rules of the built-in caller filter are always processed first, so they can be overridden in custom filter files. -In the example above, the first rule excludes lookups originating in all classes from package `com.oracle.svm` and from all of its subpackages (and their subpackages, etc.) from the generated configuration. In the next rule however, lookups from those classes that are directly in package `com.oracle.svm.tutorial` are included again. Finally, lookups from the `HostedHelper` class is excluded again. Each of these rules partially overrides the previous ones. For example, if the rules were in the reverse order, the exclusion of `com.oracle.svm.**` would be the last rule and would override all other rules. +In the example above, the first rule excludes lookups originating in all classes from package `com.oracle.svm` and from all of its subpackages (and their subpackages, etc.) from the generated configuration. +In the next rule however, lookups from those classes that are directly in package `com.oracle.svm.tutorial` are included again. +Finally, lookups from the `HostedHelper` class is excluded again. Each of these rules partially overrides the previous ones. +For example, if the rules were in the reverse order, the exclusion of `com.oracle.svm.**` would be the last rule and would override all other rules. -For testing purposes, the built-in filter for Java class library lookups can be disabled by adding the `no-builtin-caller-filter` option, but the resulting configuration files are generally unsuitable for a native image build. Similarly, the built-in filter for Java VM-internal accesses based on heuristics can be disabled with `no-builtin-heuristic-filter` and will also generally lead to less usable configuration files. For example: `-agentlib:native-image-agent=no-builtin-caller-filter,no-builtin-heuristic-filter,config-output-dir=...` +For testing purposes, the built-in filter for Java class library lookups can be disabled by adding the `no-builtin-caller-filter` option, but the resulting configuration files are generally unsuitable for a native image build. +Similarly, the built-in filter for Java VM-internal accesses based on heuristics can be disabled with `no-builtin-heuristic-filter` and will also generally lead to less usable configuration files. +For example: `-agentlib:native-image-agent=no-builtin-caller-filter,no-builtin-heuristic-filter,config-output-dir=...` ### Access Filters -Unlike the caller-based filters described above, which filter dynamic accesses based on where they originate from, _access filters_ apply to the _target_ of the access. Therefore, access filters enable directly excluding packages and classes (and their members) from the generated configuration. +Unlike the caller-based filters described above, which filter dynamic accesses based on where they originate from, _access filters_ apply to the _target_ of the access. +Therefore, access filters enable directly excluding packages and classes (and their members) from the generated configuration. -By default, all accessed classes (which also pass the caller-based filters and the built-in filters) are included in the generated configuration. Using the `access-filter-file` option, a custom filter file that follows the file structure described above can be added. The option can be specified more than once to add multiple filter files and can be combined with the other filter options. For example: `-agentlib:access-filter-file=/path/to/access-filter-file,caller-filter-file=/path/to/caller-filter-file,config-output-dir=...` +By default, all accessed classes (which also pass the caller-based filters and the built-in filters) are included in the generated configuration. +Using the `access-filter-file` option, a custom filter file that follows the file structure described above can be added. +The option can be specified more than once to add multiple filter files and can be combined with the other filter options. +For example: `-agentlib:access-filter-file=/path/to/access-filter-file,caller-filter-file=/path/to/caller-filter-file,config-output-dir=...` ### Specifying Configuration Files as Native Image Arguments -A directory containing configuration files that is not part of the class path can be specified to `native-image` via `-H:ConfigurationFileDirectories=/path/to/config-dir/`. This directory must directly contain all four files: `jni-config.json`, `reflect-config.json`, `proxy-config.json` and `resource-config.json`. A directory with the same four configuration files that is on the class path, but not in `META-INF/native-image/`, can be provided via `-H:ConfigurationResourceRoots=path/to/resources/`. Both `-H:ConfigurationFileDirectories` and `-H:ConfigurationResourceRoots` can also take a comma-separated list of directories. +A directory containing configuration files that is not part of the class path can be specified to `native-image` via `-H:ConfigurationFileDirectories=/path/to/config-dir/`. +This directory must directly contain all four files: `jni-config.json`, `reflect-config.json`, `proxy-config.json` and `resource-config.json`. +A directory with the same four configuration files that is on the class path, but not in `META-INF/native-image/`, can be provided via `-H:ConfigurationResourceRoots=path/to/resources/`. +Both `-H:ConfigurationFileDirectories` and `-H:ConfigurationResourceRoots` can also take a comma-separated list of directories. ### Injecting the Agent via the Process Environment -Altering the `java` command line to inject the agent can prove to be difficult if the Java process is launched by an application or script file, or if Java is even embedded in an existing process. In that case, it is also possible to inject the agent via the `JAVA_TOOL_OPTIONS` environment variable. This environment variable can be picked up by multiple Java processes which run at the same time, in which case each agent must write to a separate output directory with `config-output-dir`. (The next section describes how to merge sets of configuration files.) In order to use separate paths with a single global `JAVA_TOOL_OPTIONS` variable, the agent's output path options support placeholders: +Altering the `java` command line to inject the agent can prove to be difficult if the Java process is launched by an application or script file, or if Java is even embedded in an existing process. +In that case, it is also possible to inject the agent via the `JAVA_TOOL_OPTIONS` environment variable. +This environment variable can be picked up by multiple Java processes which run at the same time, in which case each agent must write to a separate output directory with `config-output-dir`. +(The next section describes how to merge sets of configuration files.) +In order to use separate paths with a single global `JAVA_TOOL_OPTIONS` variable, the agent's output path options support placeholders: ```shell export JAVA_TOOL_OPTIONS="-agentlib:native-image-agent=config-output-dir=/path/to/config-output-dir-{pid}-{datetime}/" ``` @@ -193,26 +207,30 @@ The `{pid}` placeholder is replaced with the process identifier, while `{datetim ### Trace Files -In the examples above, `native-image-agent` has been used to both keep track of the dynamic accesses in a Java VM and then to generate a set of configuration files from them. However, for a better understanding of the execution, the agent can also write a _trace file_ in JSON format that contains each individual access: +In the examples above, `native-image-agent` has been used to both keep track of the dynamic accesses in a Java VM and then to generate a set of configuration files from them. +However, for a better understanding of the execution, the agent can also write a _trace file_ in JSON format that contains each individual access: ```shell $JAVA_HOME/bin/java -agentlib:native-image-agent=trace-output=/path/to/trace-file.json ... ``` -The `native-image-configure` tool can transform trace files to configuration files that can be used in native image builds. The following command reads and processes `trace-file.json` and generates a set of configuration files in directory `/path/to/config-dir/`: +The `native-image-configure` tool can transform trace files to configuration files that can be used in native image builds. +The following command reads and processes `trace-file.json` and generates a set of configuration files in directory `/path/to/config-dir/`: ```shell native-image-configure generate --trace-input=/path/to/trace-file.json --output-dir=/path/to/config-dir/ ``` ### Interoperability -Although the agent is distributed with GraalVM, it uses the JVM Tool Interface (JVMTI) and can potentially be used with other JVMs that support JVMTI. In this case, it is necessary to provide the absolute path of the agent: +Although the agent is distributed with GraalVM, it uses the JVM Tool Interface (JVMTI) and can potentially be used with other JVMs that support JVMTI. +In this case, it is necessary to provide the absolute path of the agent: ```shell /path/to/some/java -agentpath:/path/to/graalvm/jre/lib/amd64/libnative-image-agent.so= ... ``` ### Native Image Configure Tool -When using the agent in multiple processes at the same time as described in the previous section, `config-output-dir` is a safe option, but results in multiple sets of configuration files. The `native-image-configure-launcher` tool can be used to merge these configuration files. This tool must first be built with: +When using the agent in multiple processes at the same time as described in the previous section, `config-output-dir` is a safe option, but results in multiple sets of configuration files. The `native-image-configure-launcher` tool can be used to merge these configuration files. +This tool must first be built with: ```shell native-image --macro:native-image-configure-launcher ``` diff --git a/docs/reference-manual/native-image/BuildConfiguration.md b/docs/reference-manual/native-image/BuildConfiguration.md index d7718abb2707..60303172d45b 100644 --- a/docs/reference-manual/native-image/BuildConfiguration.md +++ b/docs/reference-manual/native-image/BuildConfiguration.md @@ -18,22 +18,17 @@ Native Image supports a wide range of options to configure a native image build ## Embedding a Configuration File -A recommended way to provide configuration is to embed a -**native-image.properties** file into a project JAR file. The Native Image builder -will automatically pick up all configuration options provided anywhere below the -resource location `META-INF/native-image/` and use it to construct -`native-image` command line arguments. - -To avoid a situation when constituent parts of a project are built -with overlapping configurations, it is recommended to use "subdirectories" within -`META-INF/native-image`. That way a JAR file built from multiple maven projects -cannot suffer from overlapping `native-image` configurations. For example: +A recommended way to provide configuration is to embed a **native-image.properties** file into a project JAR file. +The Native Image builder will automatically pick up all configuration options provided anywhere below the resource location `META-INF/native-image/` and use it to construct `native-image` command line arguments. + +To avoid a situation when constituent parts of a project are built with overlapping configurations, it is recommended to use "subdirectories" within `META-INF/native-image`. +That way a JAR file built from multiple maven projects cannot suffer from overlapping `native-image` configurations. +For example: * _foo.jar_ has its configurations in `META-INF/native-image/foo_groupID/foo_artifactID` * _bar.jar_ has its configurations in `META-INF/native-image/bar_groupID/bar_artifactID` -The JAR file that contains `foo` and `bar` will then contain both configurations -without conflicting with one another. Therefore the recommended layout for -storing native image configuration data in JAR files is the following: +The JAR file that contains `foo` and `bar` will then contain both configurations without conflicting with one another. +Therefore the recommended layout for storing native image configuration data in JAR files is the following: ``` META-INF/ └── native-image @@ -42,12 +37,9 @@ META-INF/ └── native-image.properties ``` -Note that the use of `${.}` in a _native-image.properties_ file expands to the -resource location that contains that exact configuration file. This can be -useful if the _native-image.properties_ file wants to refer to resources within -its "subfolder", for example, `-H:SubstitutionResources=${.}/substitutions.json`. -Always make sure to use the option variants that take resources, i.e., use -`-H:ResourceConfigurationResources` instead of `-H:ResourceConfigurationFiles`. +Note that the use of `${.}` in a _native-image.properties_ file expands to the resource location that contains that exact configuration file. +This can be useful if the _native-image.properties_ file wants to refer to resources within its "subfolder", for example, `-H:SubstitutionResources=${.}/substitutions.json`. +Always make sure to use the option variants that take resources, i.e., use `-H:ResourceConfigurationResources` instead of `-H:ResourceConfigurationFiles`. Other options that are known to work in this context are: * `-H:DynamicProxyConfigurationResources` * `-H:JNIConfigurationResources` @@ -56,16 +48,14 @@ Other options that are known to work in this context are: * `-H:SubstitutionResources` * `-H:SerializationConfigurationResources` -By having such a composable _native-image.properties_ file, building an image -does not require any additional arguments specified on command line. It is -sufficient to just run the following command: +By having such a composable _native-image.properties_ file, building an image does not require any additional arguments specified on command line. +It is sufficient to just run the following command: ```shell $JAVA_HOME/bin/native-image -jar target/.jar ``` -To debug which configuration data gets applied for the image building, use `native-image --verbose`. This will show from where `native-image` picks up the -configurations to construct the final composite configuration command line -options for the native image builder. +To debug which configuration data gets applied for the image building, use `native-image --verbose`. +This will show from where `native-image` picks up the configurations to construct the final composite configuration command line options for the native image builder. ```shell native-image --verbose -jar build/basic-app-0.1-all.jar Apply jar:file://~/build/basic-app-0.1-all.jar!/META-INF/native-image/io.netty/common/native-image.properties @@ -89,44 +79,38 @@ supported. **Args** -Use this property if your project requires custom `native-image` command line options to build correctly. For example, the `native-image-configure-examples/configure-at-runtime-example` has `Args = --initialize-at-build-time=com.fasterxml.jackson.annotation.JsonProperty$Access` in its `native-image.properties` file to ensure the class `com.fasterxml.jackson.annotation.JsonProperty$Access` gets initialized at image build time. +Use this property if your project requires custom `native-image` command line options to build correctly. +For example, the `native-image-configure-examples/configure-at-runtime-example` has `Args = --initialize-at-build-time=com.fasterxml.jackson.annotation.JsonProperty$Access` in its `native-image.properties` file to ensure the class `com.fasterxml.jackson.annotation.JsonProperty$Access` gets initialized at image build time. **JavaArgs** -Sometimes it can be necessary to provide custom options to the JVM that runs the -native image builder. The `JavaArgs` property can be used in this case. +Sometimes it can be necessary to provide custom options to the JVM that runs the native image builder. +The `JavaArgs` property can be used in this case. **ImageName** -This property can be used to specify a user-defined name for the image. If -`ImageName` is not used, a name gets automatically chosen: +This property can be used to specify a user-defined name for the image. +If `ImageName` is not used, a name gets automatically chosen: * `native-image -jar ` has a default image name `` * `native-image -cp ... fully.qualified.MainClass` has a default image name `fully.qualified.mainclass` -Note that using `ImageName` does not prevent the user to override the name later via command line. For example, if `foo.bar` contains `ImageName=foo_app`: +Note that using `ImageName` does not prevent the user to override the name later via command line. +For example, if `foo.bar` contains `ImageName=foo_app`: * `native-image -jar foo.bar` generates the image `foo_app` but * `native-image -jar foo.bar application` generates the image `application` ### Order of Arguments Evaluation -The arguments passed to `native-image` are evaluated left-to-right. This also -extends to arguments that get passed indirectly via `META-INF/native-image` -based native image configuration. Suppose you have a JAR file that contains -_native-image.properties_ with `Args = -H:Optimize=0`. Then by using the -`-H:Optimize=2` option after `-cp ` you can override the setting that -comes from the JAR file. +The arguments passed to `native-image` are evaluated left-to-right. +This also extends to arguments that get passed indirectly via `META-INF/native-image` based native image configuration. +Suppose you have a JAR file that contains _native-image.properties_ with `Args = -H:Optimize=0`. +Then by using the `-H:Optimize=2` option after `-cp ` you can override the setting that comes from the JAR file. ### Specifying Default Options for Native Image -If there is a need to pass some options for every image build unconditionally, for -example, to always generate an image in verbose mode (`--verbose`), you can -make use of the `NATIVE_IMAGE_CONFIG_FILE` environment variable. -If it is set to a Java properties file, the Native Image builder will use the -default setting defined in there on each invocation. Write a -configuration file and export -`NATIVE_IMAGE_CONFIG_FILE=$HOME/.native-image/default.properties` in -`~/.bash_profile`. Every time `native-image` gets used, it will implicitly use -the arguments specified as `NativeImageArgs`, plus the arguments specified on the -command line. Here is an example of a configuration file, saved as -`~/.native-image/default.properties`: +If there is a need to pass some options for every image build unconditionally, for example, to always generate an image in verbose mode (`--verbose`), you can make use of the `NATIVE_IMAGE_CONFIG_FILE` environment variable. +If it is set to a Java properties file, the Native Image builder will use the default setting defined in there on each invocation. +Write a configuration file and export `NATIVE_IMAGE_CONFIG_FILE=$HOME/.native-image/default.properties` in `~/.bash_profile`. +Every time `native-image` gets used, it will implicitly use the arguments specified as `NativeImageArgs`, plus the arguments specified on the command line. +Here is an example of a configuration file, saved as `~/.native-image/default.properties`: ``` NativeImageArgs = --configurations-path /home/user/custom-image-configs \ @@ -146,9 +130,9 @@ export NATIVE_IMAGE_USER_HOME= $HOME/.local/share/native-image The native image build runs on the Java HotSpot VM and uses the memory management of the underlying platform. The usual Java HotSpot command-line options for garbage collection apply to the native image builder. -During the native image build, the representation of a whole program is created to -figure out which classes and methods will be used at run time. It is a -computationally intensive process. The default values for memory usage at image build time are: +During the native image build, the representation of a whole program is created to figure out which classes and methods will be used at run time. +It is a computationally intensive process. +The default values for memory usage at image build time are: ``` -Xss10M \ -Xms1G \ @@ -164,21 +148,16 @@ Check other related options to the native image builder from the `native-image - ## Runtime vs Build-Time Initialization -Building your application into a native image allows you to decide which parts -of your application should be run at image build time and which parts have to -run at image run time. +Building your application into a native image allows you to decide which parts of your application should be run at image build time and which parts have to run at image run time. -All class-initialization code (static initializers and static -field initialization) of the application you build an image for is executed -at image run time by default. Sometimes it is beneficial to allow class -initialization code to get executed at image build time for faster startup (e.g., -if some static fields get initialized to run-time independent data). This can be -controlled with the following `native-image` options: +All class-initialization code (static initializers and static field initialization) of the application you build an image for is executed at image run time by default. +Sometimes it is beneficial to allow class initialization code to get executed at image build time for faster startup (e.g., if some static fields get initialized to run-time independent data). +This can be controlled with the following `native-image` options: * `--initialize-at-build-time=` * `--initialize-at-run-time=` -In addition to that, arbitrary computations are allowed at build time that can be put into `ImageSingletons` that are -accessible at image run time. For more information please have a look at [Native Image configuration examples](https://github.com/graalvm/graalvm-demos/tree/master/native-image-configure-examples). +In addition to that, arbitrary computations are allowed at build time that can be put into `ImageSingletons` that are accessible at image run time. +For more information please have a look at [Native Image configuration examples](https://github.com/graalvm/graalvm-demos/tree/master/native-image-configure-examples). For more information, continue reading to the [Class Initialization in Native Image](ClassInitialization.md) guide. diff --git a/docs/reference-manual/native-image/C-API.md b/docs/reference-manual/native-image/C-API.md index d662844d550e..a0611d270dfb 100644 --- a/docs/reference-manual/native-image/C-API.md +++ b/docs/reference-manual/native-image/C-API.md @@ -79,6 +79,4 @@ int graal_detach_thread(graal_isolatethread_t* thread); */ int graal_tear_down_isolate(graal_isolatethread_t* thread); ``` -In addition to the C level API, there is also a way to initialize an isolate -from Java and thus use Java and Native Image to -[implement native methods in Java](ImplementingNativeMethodsInJavaWithSVM.md). +In addition to the C level API, there is also a way to initialize an isolate from Java and thus use Java and Native Image to [implement native methods in Java](ImplementingNativeMethodsInJavaWithSVM.md). diff --git a/docs/reference-manual/native-image/CertificateManagement.md b/docs/reference-manual/native-image/CertificateManagement.md index bf75632ad19e..e5cfd436e51a 100644 --- a/docs/reference-manual/native-image/CertificateManagement.md +++ b/docs/reference-manual/native-image/CertificateManagement.md @@ -6,60 +6,40 @@ permalink: /reference-manual/native-image/CertificateManagement/ --- # Certificate Management in Native Image -Native-image provides multiple ways to specify the certificate file used to -define the default TrustStore. In the following sections we describe the -available buildtime and runtime options. Note the default behavior for -native-image is to capture and use the default TrustStore from the buildtime -host environment. +Native Image provides multiple ways to specify the certificate file used to define the default TrustStore. +In the following sections we describe the available build-time and run-time options. +Note: The default behavior for `native-image` is to capture and use the default TrustStore from the build-time host environment. -## Buildtime Options +## Build-time Options -During the image building process, native-image captures the host environment's -default TrustStore and embeds it into the native image. This TrustStore is -by default created from the root certificate file provided within the JDK, but -can be changed to use a different certificate file by setting the buildtime -system property "javax.net.ssl.trustStore" (see [Properties](Properties.md) for -how to do so). +During the image building process, the `native-image` builder captures the host environment's default TrustStore and embeds it into the native executable. +This TrustStore is by default created from the root certificate file provided within the JDK, but can be changed to use a different certificate file by setting the build-time system property `javax.net.ssl.trustStore` (see [Properties](Properties.md) for how to do it). -Since the contents of the buildtime certificate file is embedded into the image -executable, the file itself does not need to present in the target environment. +Since the contents of the build-time certificate file is embedded into the native executable, the file itself does not need to be present in the target environment. -## Runtime Options +## Run-time Options -The certificate file can also be changed dynamically at runtime via setting -the "javax.net.ssl.trustStore\*" system properties. +The certificate file can also be changed dynamically at run time via setting the `javax.net.ssl.trustStore\*` system properties. -If any of the following system properties are set during image execution, -native-image also requires "javax.net.ssl.trustStore" to be set and for it -to point to an accessible certificate file: -- javax.net.ssl.trustStore -- javax.net.ssl.trustStoreType -- javax.net.ssl.trustStoreProvider -- javax.net.ssl.trustStorePassword +If any of the following system properties are set during the image execution, `native-image` also requires `javax.net.ssl.trustStore` to be set, and for it to point to an accessible certificate file: +- `javax.net.ssl.trustStore` +- `javax.net.ssl.trustStoreType` +- `javax.net.ssl.trustStoreProvider` +- `javax.net.ssl.trustStorePassword` -If any of these properties are set and "javax.net.ssl.trustStore" does not point -to an accessible file, then an UnsupportedFeatureError will be thrown. +If any of these properties are set and `javax.net.ssl.trustStore` does not point to an accessible file, then an `UnsupportedFeatureError` will be thrown. -Note that this behavior is different than OpenJDK. When the -"javax.net.ssl.trustStore" system property is unset/invalid, OpenJDK will -fallback to using a certificate file shipped within the JDK; however, such -files will not be present alongside the image executable and hence cannot be -used as a fallback. +Note that this behavior is different than OpenJDK. +When the `javax.net.ssl.trustStore` system property is unset or invalid, OpenJDK will fallback to using a certificate file shipped within the JDK. +However, such files will not be present alongside the image executable and hence cannot be used as a fallback. -During the execution, it also possible to dynamically change the -"javax.net.ssl.trustStore\*" properties and for the default TrustStore to be -updated accordingly. +During the execution, it also possible to dynamically change the `javax.net.ssl.trustStore\*` properties and for the default TrustStore to be updated accordingly. -Finally, whenever all of the "javax.net.ssl.trustStore\*" system properties -listed above are unset, the default TrustStore will be the one captured during -buildtime, as described in the [prior section](#buildtime-options). +Finally, whenever all of the `javax.net.ssl.trustStore\*` system properties listed above are unset, the default TrustStore will be the one captured during the build time, as described in the [prior section](#build-time-options). ## Untrusted Certificates -During the image building process, a list of untrusted certificates is loaded -from the file /lib/security/blacklisted.certs. This file is used -when validating certificates at both buildtime and runtime. In other words, -when a new certificate file is specified at runtime via setting the -"javax.net.ssl.trustStore\*" system properties, the new certificates will still -be checked against the /lib/security/blacklisted.certs loaded at -image buildtime. +During the image building process, a list of untrusted certificates is loaded from the file `/lib/security/blacklisted.certs`. +This file is used when validating certificates at both build time and run time. +In other words, when a new certificate file is specified at run time via setting the `javax.net.ssl.trustStore\*` system properties, the new certificates will still be checked against the `/lib/security/blacklisted.certs` loaded at +image build time. diff --git a/docs/reference-manual/native-image/ClassInitialization.md b/docs/reference-manual/native-image/ClassInitialization.md index 5b457b014fca..225191923327 100644 --- a/docs/reference-manual/native-image/ClassInitialization.md +++ b/docs/reference-manual/native-image/ClassInitialization.md @@ -19,7 +19,9 @@ Access to the static fields that were initialized at build time is transparent t Specifying class initialization policies can be complicated due to the following constraints that come from class initialization semantics: * When a class is initialized, all super classes and super interfaces with default methods must also be initialized. -Interfaces without default methods, however, are not initialized. To describe this, a short-term "relevant supertype" is used furhter, and a relevant subtype for subtypes of classes and interfaces with default methods. +Interfaces without default methods, however, are not initialized. +To describe this, a short-term "relevant supertype" is used furhter, and a relevant subtype for subtypes of classes and interfaces with default methods. + * Relevant supertypes of types initialized at build time must also be initialized at build time. * Relevant subtypes of types initialized at run time must also be initialized at run time. * No instances classes that are initialized at run time must be present in the image. @@ -31,7 +33,8 @@ To enjoy the complete out-of-the-box experience of Native Image and still get th * [Explicitly Specifying Class Initialization](#explicitly-specifying-class-initialization) To track which classes were initialized and why, one can use the flag `-H:+PrintClassInitialization`. -This flag greatly helps to configure the image build to work as intended. The goal is to have as many classes as possible initialized at build time, yet keep the correct semantics of the program. +This flag greatly helps to configure the image build to work as intended. +The goal is to have as many classes as possible initialized at build time, yet keep the correct semantics of the program. ## Build-Time Initialization of Native Image Runtime diff --git a/docs/reference-manual/native-image/DynamicProxy.md b/docs/reference-manual/native-image/DynamicProxy.md index c56dadc05175..0ff440024398 100644 --- a/docs/reference-manual/native-image/DynamicProxy.md +++ b/docs/reference-manual/native-image/DynamicProxy.md @@ -16,7 +16,8 @@ See also the [guide on assisted configuration of Java resources and other dynami ## Automatic Detection -Native Image employs a simple static analysis that detects calls to `java.lang.reflect.Proxy.newProxyInstance(ClassLoader, Class[], InvocationHandler)` and `java.lang.reflect.Proxy.getProxyClass(ClassLoader, Class[])`, then tries to determine the list of interfaces that define dynamic proxies automatically. Given the list of interfaces, Native Image generates proxy classes at image build time and adds them to the native image heap. +Native Image employs a simple static analysis that detects calls to `java.lang.reflect.Proxy.newProxyInstance(ClassLoader, Class[], InvocationHandler)` and `java.lang.reflect.Proxy.getProxyClass(ClassLoader, Class[])`, then tries to determine the list of interfaces that define dynamic proxies automatically. +Given the list of interfaces, Native Image generates proxy classes at image build time and adds them to the native image heap. In addition to generating the dynamic proxy class, the constructor of the generated class that takes a `java.lang.reflect.InvocationHandler` argument, i.e., the one reflectively invoked by `java.lang.reflect.Proxy.newProxyInstance(ClassLoader, Class[], InvocationHandler)`, is registered for reflection so that dynamic proxy instances can be allocated at run time. The analysis is limited to situations where the list of interfaces comes from a constant array or an array that is allocated in the same method. @@ -90,9 +91,9 @@ For the exceptional cases where the analysis cannot discover the interface array ## Manual Configuration -Dynamic proxy classes can be generated at native image build time by specifying the list of interfaces that they implement. Native Image provides two options for this purpose: `-H:DynamicProxyConfigurationFiles=` and `-H:DynamicProxyConfigurationResources=`. +Dynamic proxy classes can be generated at native image build time by specifying the list of interfaces that they implement. +Native Image provides two options for that: `-H:DynamicProxyConfigurationFiles=` and `-H:DynamicProxyConfigurationResources=`. These options accept JSON files whose structure is an array of arrays of fully qualified interface names. For example: -These options accept JSON files whose structure is an array of arrays of fully qualified interface names. For example: ```json [ ["java.lang.AutoCloseable", "java.util.Comparator"], @@ -101,6 +102,8 @@ These options accept JSON files whose structure is an array of arrays of fully q ] ``` +Note that the order of the specified proxy interfaces is significant: two requests for a `Proxy` class with the same combination of interfaces but in a different order will result in two distinct behaviours (for more detailed information, refer to [`Proxy Class `javadoc](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/reflect/Proxy.html). + The `java.lang.reflect.Proxy` API also allows creation of a dynamic proxy that does not implement any user provided interfaces. Therefore the following is a valid configuration: ```json [ diff --git a/docs/reference-manual/native-image/HostedvsRuntimeOptions.md b/docs/reference-manual/native-image/HostedvsRuntimeOptions.md index 1c15425aa568..27a9fc34f329 100644 --- a/docs/reference-manual/native-image/HostedvsRuntimeOptions.md +++ b/docs/reference-manual/native-image/HostedvsRuntimeOptions.md @@ -6,8 +6,7 @@ permalink: /reference-manual/native-image/HostedvsRuntimeOptions/ --- # Native Image Hosted and Runtime Options -Along with all the options listed in the [Options](Options.md) -guide, Native Image also distinguishes hosted and runtime options. +Along with all the options listed in the [Options](Options.md) guide, Native Image also distinguishes hosted and runtime options. * Hosted options: configure a native image build, i.e., influence what is put into the image and how the image is built. These are set using the prefix `-H:` on the command line. @@ -19,15 +18,11 @@ For developer documentation on how to define and use options, read the documenta ## List of Useful Options ### Graph Dumping -Native Image re-used the GraalVM options for graph dumping, logging, counters, -and everything else in the GraalVM debug environment. These GraalVM options can -be used both as hosted options (if you want to dump graphs of the native image -builder), and as runtime options (if you want to dump graphs during dynamic +Native Image re-used the GraalVM options for graph dumping, logging, counters, and everything else in the GraalVM debug environment. +These GraalVM options can be used both as hosted options (if you want to dump graphs of the native image builder), and as runtime options (if you want to dump graphs during dynamic compilation at runtime). -The GraalVM compiler options that work as expected include `Dump`, `DumpOnError`, `Log`, -`MethodFilter`, and the options to specify file names and ports for the dump -handlers. +The GraalVM compiler options that work as expected include `Dump`, `DumpOnError`, `Log`, `MethodFilter`, and the options to specify file names and ports for the dump handlers. For example: * To dump the compiler graphs of the native image builder: `-H:Dump= -H:MethodFilter=ClassName.MethodName`. diff --git a/docs/reference-manual/native-image/ImplementingNativeMethodsInJavaWithSVM.md b/docs/reference-manual/native-image/ImplementingNativeMethodsInJavaWithSVM.md index d5bf3ac44288..89f20feb3201 100644 --- a/docs/reference-manual/native-image/ImplementingNativeMethodsInJavaWithSVM.md +++ b/docs/reference-manual/native-image/ImplementingNativeMethodsInJavaWithSVM.md @@ -6,20 +6,15 @@ permalink: /reference-manual/native-image/ImplementingNativeMethodsInJavaWithSVM --- # Implementing Native Methods in Java with Native Image -Native Image can be used to implement low-level system operations in Java and -make them available via JNI to Java code executing on a standard JVM. As -a result one can use the same language to write the application logic -as well as the system calls. +Native Image can be used to implement low-level system operations in Java and make them available via JNI to Java code executing on a standard JVM. +As a result one can use the same language to write the application logic as well as the system calls. -Note that this document describes the opposite of what is commonly done via JNI: -usually low-level system operations are implemented in C and invoked from Java -using JNI. If you are interested in how Native Image supports the common use case, -continue reading to the [Native Image JNI support](JNI.md) guide instead. +Note that this document describes the opposite of what is commonly done via JNI: usually low-level system operations are implemented in C and invoked from Java using JNI. +If you are interested in how Native Image supports the common use case, continue reading to the [Native Image JNI support](JNI.md) guide instead. ## Create a Shared Library -First of all one has to use the `native-image` builder to generate a shared library -with some JNI-compatible [entry points](README.md#build-a-shared-library). +First of all one has to use the `native-image` builder to generate a shared library with some JNI-compatible [entry points](README.md#build-a-shared-library). Start with the Java code: ```java package org.pkg.implnative; @@ -34,20 +29,15 @@ public final class NativeImpl { } } ``` -After being processed by the `native-image` builder, the code -[exposes a C function](C-API.md) `Java_org_pkg_apinative_Native_add` -(the name follows conventions of JNI that will be handy later) and -a Native Image signature typical for JNI methods. The first parameter -is a reference to the `JNIEnv*` value. The second parameter is a reference -to the `jclass` value for the class declaring the method. The third parameter is a -portable (e.g., `long`) identifier of the [Native Image isolatethread](C-API.md). -The rest of the parameters are the actual parameters of the Java `Native.add` -method described in the next section. Compile the code with the `--shared` option: +After being processed by the `native-image` builder, the code [exposes a C function](C-API.md) `Java_org_pkg_apinative_Native_add` (the name follows conventions of JNI that will be handy later) and a Native Image signature typical for JNI methods. +The first parameter is a reference to the `JNIEnv*` value. +The second parameter is a reference to the `jclass` value for the class declaring the method. +The third parameter is a portable (e.g., `long`) identifier of the [Native Image isolatethread](C-API.md). +The rest of the parameters are the actual parameters of the Java `Native.add` method described in the next section. Compile the code with the `--shared` option: ```shell $GRAALVM/bin/native-image --shared -H:Name=libnativeimpl -cp nativeimpl ``` -The `libnativeimpl.so` is generated. We are ready to use it from standard -Java code. +The `libnativeimpl.so` is generated. We are ready to use it from standard Java code. ## Bind a Java Native Method @@ -59,16 +49,14 @@ public final class Native { private static native int add(long isolateThreadId, int a, int b); } ``` -The package name of the class, as well as the name of the method, has to correspond -(after the [JNI mangling](https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/design.html)) -to the name of the `@CEntryPoint` introduced previously. The first argument is -a portable (e.g., `long`) identifier of the Native Image isolate thread. The rest of the arguments -match the parameters of the entry point. +The package name of the class, as well as the name of the method, has to correspond (after the [JNI mangling](https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/design.html)) to the name of the `@CEntryPoint` introduced previously. +The first argument is a portable (e.g., `long`) identifier of the Native Image isolate thread. +The rest of the arguments match the parameters of the entry point. ## Loading the Native Library -The next step is to bind the JDK with the generated `.so` library. For example, -make sure the implementation of the native `Native.add` method is loaded. +The next step is to bind the JDK with the generated `.so` library. +For example, make sure the implementation of the native `Native.add` method is loaded. Simple `load` or `loadLibrary` calls will do: ```java public static void main(String[] args) { @@ -76,27 +64,23 @@ public static void main(String[] args) { // ... } ``` -This is assuming your `LD_LIBRARY_PATH` environment variable is specified, -or the `java.library.path` Java property is properly set. +This is assuming your `LD_LIBRARY_PATH` environment variable is specified, or the `java.library.path` Java property is properly set. ## Initializing a Native Image Isolate -Before making calls to the `Native.add` method, we need to create a Native Image -isolate. Native Image provides a special built-in to allow that: -`CEntryPoint.Builtin.CREATE_ISOLATE`. Define another method along your other -existing `@CEntryPoint` methods. Let it return `IsolateThread` and take no parameters: +Before making calls to the `Native.add` method, we need to create a Native Image isolate. +Native Image provides a special built-in to allow that: `CEntryPoint.Builtin.CREATE_ISOLATE`. +Define another method along your other existing `@CEntryPoint` methods. +Let it return `IsolateThread` and take no parameters: ```java public final class NativeImpl { @CEntryPoint(name = "Java_org_pkg_apinative_Native_createIsolate", builtin=CEntryPoint.Builtin.CREATE_ISOLATE) public static native IsolateThread createIsolate(); } ``` -Native Image then generates default native implementation of the -method into the final `.so` library. -The method initializes the Native Image runtime and -returns a portable identification, e.g., `long`, to hold -an instance of a [Native Image isolatethread](C-API.md). The isolate thread can then be used for -multiple invocations of the native part of your code: +Native Image then generates default native implementation of the method into the final `.so` library. +The method initializes the Native Image runtime and returns a portable identification, e.g., `long`, to hold an instance of a [Native Image isolatethread](C-API.md). +The isolate thread can then be used for multiple invocations of the native part of your code: ```java package org.pkg.apinative; @@ -115,19 +99,16 @@ public final class Native { private static native long createIsolate(); } ``` -The standard JVM is started. It initializes a Native Image isolate, -attaches the current thread to the isolate, and the universal answer `42` is -then computed three times inside of the isolate. +The standard JVM is started. It initializes a Native Image isolate, attaches the current thread to the isolate, and the universal answer `42` is then computed three times inside of the isolate. ## Calling JVM from Native Java -There is a detailed [tutorial on the C interface](https://github.com/oracle/graal/blob/master/substratevm/src/com.oracle.svm.tutorial/src/com/oracle/svm/tutorial/CInterfaceTutorial.java) of Native Image. The following example shows how to make a callback to JVM. +There is a detailed [tutorial on the C interface](https://github.com/oracle/graal/blob/master/substratevm/src/com.oracle.svm.tutorial/src/com/oracle/svm/tutorial/CInterfaceTutorial.java) of Native Image. +The following example shows how to make a callback to JVM. -In the classical setup, when C needs to call into JVM, it uses a [jni.h](JNI.md) -header file. The file defines essential JVM structures (like `JNIEnv`) as well as -functions one can invoke to inspect classes, access fields, and call methods -in the JVM. In order to call these functions from the `NativeImpl` class in the above -example, you need to define appropriate Java API wrappers of the `jni.h` concepts: +In the classical setup, when C needs to call into JVM, it uses a [jni.h](JNI.md) header file. +The file defines essential JVM structures (like `JNIEnv`) as well as functions one can invoke to inspect classes, access fields, and call methods in the JVM. +In order to call these functions from the `NativeImpl` class in the above example, you need to define appropriate Java API wrappers of the `jni.h` concepts: ```java @CContext(JNIHeaderDirectives.class) @@ -172,20 +153,14 @@ interface JMethodID extends PointerBase { } ``` -Leaving aside the meaning of `JNIHeaderDirectives` for now, the rest -of the interfaces are type-safe representations of the C pointers found in the -`jni.h` file. `JClass`, `JMethodID`, and `JObject` are all pointers. Thanks to -the above definitions, you now have Java interfaces to represent -instances of these objects in your native Java code in a type-safe way. - -The core part of any [JNI](JNI.md) API is the set of functions one can call -when talking to the JVM. There are dozens of them, but in the `JNINativeInterface` -definition, you just define wrappers for those few that are needed in the example. -Again, give them proper types, so in your native Java code you can use -`GetMethodId.find(...)`, `CallStaticVoidMethod.call(...)`, etc. In addition, -there is another important part missing in the puzzle - the `jvalue` union type -wrapping all the possible Java primitive and object types. Here are definitions -of its getters and setters: +Leaving aside the meaning of `JNIHeaderDirectives` for now, the rest of the interfaces are type-safe representations of the C pointers found in the `jni.h` file. `JClass`, `JMethodID`, and `JObject` are all pointers. +Thanks to the above definitions, you now have Java interfaces to represent instances of these objects in your native Java code in a type-safe way. + +The core part of any [JNI](JNI.md) API is the set of functions one can call when talking to the JVM. +There are dozens of them, but in the `JNINativeInterface` definition, you just define wrappers for those few that are needed in the example. +Again, give them proper types, so in your native Java code you can use `GetMethodId.find(...)`, `CallStaticVoidMethod.call(...)`, etc. +In addition, there is another important part missing in the puzzle - the `jvalue` union type wrapping all the possible Java primitive and object types. +Here are definitions of its getters and setters: ```java @CContext(JNIHeaderDirectives.class) @@ -215,13 +190,9 @@ interface JValue extends PointerBase { JValue addressOf(int index); } ``` -The `addressOf` method is a special Native Image construct used to perform -C pointer arithmetics. Given a pointer, one can treat it as the initial element of -an array, then, for example, use `addressOf(1)` to access the subsequent element. -With this you have all the API needed to make a callback - redefine -the previously introduced `NativeImpl.add` method to accept properly typed -pointers, and then use these pointers to invoke a JVM method before computing -the sum of `a + b`: +The `addressOf` method is a special Native Image construct used to perform C pointer arithmetics. +Given a pointer, one can treat it as the initial element of an array, then, for example, use `addressOf(1)` to access the subsequent element. +With this you have all the API needed to make a callback - redefine the previously introduced `NativeImpl.add` method to accept properly typed pointers, and then use these pointers to invoke a JVM method before computing the sum of `a + b`: ```java @CEntryPoint(name = "Java_org_pkg_apinative_Native_add") @@ -250,13 +221,9 @@ static int add(JNIEnvironment env, JClass clazz, @CEntryPoint.IsolateThreadConte } ``` -The above example seeks a static method `hello` and invokes it with eight -`JValue` parameters in an array reserved by `StackValue.get` -on the stack. Individual parameters are accessed by use of -the `addressOf` operator and filled with appropriate primitive values -before the call happens. The method `hello` is defined in the class `Native` -and prints values of all parameters to verify they are properly -propagated from the `NativeImpl.add` caller: +The above example seeks a static method `hello` and invokes it with eight `JValue` parameters in an array reserved by `StackValue.get` on the stack. +Individual parameters are accessed by use of the `addressOf` operator and filled with appropriate primitive values before the call happens. +The method `hello` is defined in the class `Native` and prints values of all parameters to verify they are properly propagated from the `NativeImpl.add` caller: ``` public class Native { @@ -268,11 +235,9 @@ public class Native { ``` There is just one final piece to explain: the `JNIHeaderDirectives`. -The Native Image C interface needs to understand the layout of the C structures. It -needs to know at which offset of `JNINativeInterface` structure it can find -the pointer to the `GetMethodId` function. To do so, it needs `jni.h` and additional -files during compilation. One can specify them by `@CContext` annotation and -implementation of its `Directives`: +The Native Image C interface needs to understand the layout of the C structures. +It needs to know at which offset of `JNINativeInterface` structure it can find the pointer to the `GetMethodId` function. +To do so, it needs `jni.h` and additional files during compilation. One can specify them by `@CContext` annotation and implementation of its `Directives`: ```java final class JNIHeaderDirectives implements CContext.Directives { @@ -300,10 +265,7 @@ final class JNIHeaderDirectives implements CContext.Directives { } ``` -The good thing is that `jni.h` is inside of every JDK, so one can use the -`java.home` property to locate the necessary header files. The actual logic -can, of course, be made more robust and OS-independent. +The good thing is that `jni.h` is inside of every JDK, so one can use the `java.home` property to locate the necessary header files. +The actual logic can, of course, be made more robust and OS-independent. -Implementing any JVM native method in Java and/or making callbacks to the JVM -with Native Image should now be as easy as expanding upon the given example -and invoking `native-image`. +Implementing any JVM native method in Java and/or making callbacks to the JVM with Native Image should now be as easy as expanding upon the given example and invoking `native-image`. diff --git a/docs/reference-manual/native-image/JNI.md b/docs/reference-manual/native-image/JNI.md index b658101f7818..18099d071af9 100644 --- a/docs/reference-manual/native-image/JNI.md +++ b/docs/reference-manual/native-image/JNI.md @@ -53,7 +53,8 @@ class JNIRegistrationFeature implements Feature { } } ``` -To activate the custom feature `--features=` needs to be passed to native-image. [Native Image Build Configuration](BuildConfiguration.md) explains how this can be automated with a `native-image.properties` file in `META-INF/native-image`. +To activate the custom feature `--features=` needs to be passed to native-image. +[Native Image Build Configuration](BuildConfiguration.md) explains how this can be automated with a `native-image.properties` file in `META-INF/native-image`. ## Object Handles JNI does not permit direct access to Java objects. diff --git a/docs/reference-manual/native-image/LLVMBackend.md b/docs/reference-manual/native-image/LLVMBackend.md index e25dd6aacaa0..15e22d898bf8 100644 --- a/docs/reference-manual/native-image/LLVMBackend.md +++ b/docs/reference-manual/native-image/LLVMBackend.md @@ -6,7 +6,8 @@ permalink: /reference-manual/native-image/LLVMBackend/ --- # LLVM Backend for Native Image -Native Image includes an alternative backend which uses the [LLVM intermediate representation](https://llvm.org/docs/LangRef.html) and the [LLVM compiler](http://llvm.org/docs/CommandGuide/llc.html) to produce native executables. To use it, add the `-H:CompilerBackend=llvm` option to the Native Image invocation. +Native Image includes an alternative backend which uses the [LLVM intermediate representation](https://llvm.org/docs/LangRef.html) and the [LLVM compiler](http://llvm.org/docs/CommandGuide/llc.html) to produce native executables. +To use it, add the `-H:CompilerBackend=llvm` option to the Native Image invocation. The LLVM backend requires GraalVM's LLVM toolchain to be installed (with `gu install llvm-toolchain`). @@ -29,13 +30,15 @@ The LLVM backend requires GraalVM's LLVM toolchain to be installed (with `gu ins ## How to Add a Target Architecture to GraalVM Using LLVM Backend -An interesting use case for the LLVM backend is to target a new architecture without having to implement a complete new backend for Native Image. The following are the necessary steps to achieve this at the moment. +An interesting use case for the LLVM backend is to target a new architecture without having to implement a complete new backend for Native Image. +The following are the necessary steps to achieve this at the moment. ### Target-Specific LLVM Settings There are a few instances where the GraalVM code has to go deeper than the target-independent nature of LLVM. These are most notably inline assembly snippets to implement direct register accesses and direct register jumps (for trampolines), as well as precisions about the structure of the stack frames of the code emitted by LLVM. -All in all, this represents less than a dozen simple values to be set for each new target. It is our goal that in the future this will be the only addition needed to support a new target. +All in all, this represents less than a dozen simple values to be set for each new target. +It is our goal that in the future this will be the only addition needed to support a new target. _([Complete set of values for AArch64](https://github.com/oracle/graal/commit/80cceec6f6299181d94e844eb22dffbef3ecc9e4))_ diff --git a/docs/reference-manual/native-image/Limitations.md b/docs/reference-manual/native-image/Limitations.md index 23974f379729..38bca092e4c3 100644 --- a/docs/reference-manual/native-image/Limitations.md +++ b/docs/reference-manual/native-image/Limitations.md @@ -19,7 +19,9 @@ If an application is not optimizable, then a so-called fallback image is generat ## Class Metadata Features (Require Configuration) -The following features generally require the configuration at image build time in order to use the closed-world optimization. This configuration ensures that the minimum amount of space necessary is used in the native image binary. +The following features generally require the configuration at image build time in order to use the closed-world optimization. +This configuration ensures that the minimum amount of space necessary is used in the native image binary. + If one of the following features is used without providing a configuration at image build time, a fallback image is generated. ### Dynamic Class Loading @@ -47,7 +49,8 @@ For more details, read the [Dynamic Proxies support](DynamicProxy.md) guide. ### JNI (Java Native Interface) Native code may access Java objects, classes, methods and fields by name, in a similar way to using the reflection API in Java code. -For the same reasons, any Java artifacts accessed by name via JNI must be specified during a native image generation in a [configuration file](BuildConfiguration.md). For more details, read the [JNI Implementation](JNI.md) guide. +For the same reasons, any Java artifacts accessed by name via JNI must be specified during a native image generation in a [configuration file](BuildConfiguration.md). +For more details, read the [JNI Implementation](JNI.md) guide. As an alternative, and in addition to JNI, Native Image provides its own native interface that is much simpler than JNI and with lower overhead. It allows calls between Java and C, and access of C data structures from Java code. @@ -56,8 +59,8 @@ For more details, read the [JavaDoc of the package `org.graalvm.nativeimage.c` a ### Serialization Java serialization requires class metadata information in order to function and must be specified during a native image generation in a [configuration file](BuildConfiguration.md). -However, Java serialization has been a persistent source of security vulnerabilities. The Java architects have announced that the existing serialization mechanism will be replaced -with a new mechanism avoiding these problems in the near future. +However, Java serialization has been a persistent source of security vulnerabilities. +The Java architects have announced that the existing serialization mechanism will be replaced with a new mechanism avoiding these problems in the near future. ## Features Incompatible with Closed-World Optimization @@ -80,16 +83,12 @@ Native Image implements some Java features in a different way than the Java HotS ### Signal Handlers -Registering a signal handler requires to start a new thread that handles the -signal and invokes the shutdown hooks. By default, no signal handlers are -registered when building a native image, unless they are registered explicitly by the user. -For example, it is not recommended to register the default signal -handlers when building a shared library, but it is desirable to include -signal handlers when building native images for containerized environments, like -Docker containers. +Registering a signal handler requires to start a new thread that handles the signal and invokes the shutdown hooks. +By default, no signal handlers are registered when building a native image, unless they are registered explicitly by the user. +For example, it is not recommended to register the default signal handlers when building a shared library, but it is desirable to include signal handlers when building native images for containerized environments, like Docker containers. -To register the default signal handlers, pass the `--install-exit-handlers` option to the -`native-image` builder. This option gives you the same signal handlers as a JVM does. +To register the default signal handlers, pass the `--install-exit-handlers` option to the `native-image` builder. +This option gives you the same signal handlers as a JVM does. ### Class Initializers By default, classes are initialized at image run time. @@ -99,8 +98,7 @@ Class initialization behaviour can be adjusted using the options `--initialize- See `native-image --help` for details. Classes of the JDK class libraries are handled for you and do not need special consideration from the user. -Native Image users should be aware that class initialization at image build time -may break specific assumptions in existing code. +Native Image users should be aware that class initialization at image build time may break specific assumptions in existing code. For example, files loaded in a class initializer may not be in the same place at image build time as at image run time. Also, certain objects such as a file descriptors or running threads must not be stored into a native image binary. If such objects are reachable at image build time, image generation fails with an error. diff --git a/docs/reference-manual/native-image/MemoryManagement.md b/docs/reference-manual/native-image/MemoryManagement.md index 6e3fb95e37f8..f89dbf37e673 100644 --- a/docs/reference-manual/native-image/MemoryManagement.md +++ b/docs/reference-manual/native-image/MemoryManagement.md @@ -48,7 +48,7 @@ Note: The maximum heap size is only the upper limit for the Java heap and not ne The *Serial GC* is optimized for low footprint and small Java heap sizes. If no other GC is specified, the Serial GC will be used implicitly as the default on both GraalVM Community and Enterprise Edition. -Since GraalVM 20.3, it is also possible to explicitly enable the Serial GC by passing the option `--gc=serial` to the native image builder. +It is also possible to explicitly enable the Serial GC by passing the option `--gc=serial` to the native image builder. ```shell # Build a native image that uses the serial GC with default settings @@ -62,11 +62,13 @@ It divides the Java heap into a young and an old generation. Each generation consists of a set of equally sized chunks, each a contiguous range of virtual memory. Those chunks are the GC-internal unit for memory allocation and memory reclamation. -The young generation is reserved for the allocation of new objects and when this part becomes full, a young collection is triggered. -Objects that are alive in the young generation, will be moved to the old generation, thus freeing up the young generation for subsequent object allocations. -When the old generation becomes full, a full collection is triggered. -Typically, a young collection is much faster than an full collection, however doing full collections is important for keeping the memory footprint low. -By default, the GC tries to balance the time that is spent in young and full collections. +The young generation contains recently created objects and is divided into the _eden_ and _survivor_ regions. +New objects are allocated in the eden region, and when this region is full, a young collection is triggered. +Objects that are alive in the eden region will be moved to the survivor region, and alive objects in the survivor region stay in that region until they reach a certain age (have survived a certain number of collections), at which time they are moved to the old generation. +When the old generation becomes full, a full collection is triggered that reclaims the space of unused objects in both the young and old generations. +Typically, a young collection is much faster than a full collection, however doing full collections is important for keeping the memory footprint low. +By default, the Serial GC tries to find a size for the generations that provides good throughput, but to not increase sizes further when doing so gives diminishing returns. +It also tries to maintain a ratio between the time spent in young collections and in full collections to keep the footprint small. If no maximum Java heap size is specified, a native image that uses the Serial GC will set its maximum Java heap size to 80% of the physical memory size. For example, on a machine with 4GB of RAM, the maximum Java heap size will be set to 3.2GB. @@ -75,33 +77,43 @@ Note that this is just the maximum value. Depending on the application, the amount of actually used Java heap memory can be much lower. To override this default behavior, either specify a value for `-XX:MaximumHeapSizePercent` or explicitly set the maximum [Java heap size](#java-heap-size). +Note that GraalVM releases up to (and including) 21.3 use a different default configuration for the Serial GC with no survivor regions, a young generation that is limited to 256 MB, and a default collection policy that balances the time that is spent in young collections and old collections. +This configuration can be enabled with: `-H:InitialCollectionPolicy=BySpaceAndTime` + +Be mindful that the GC needs some extra memory when performing a garbage collection (2x of the maximum heap size is the worst case, usually, it is significantly less). +Therefore, the resident set size, RSS, can increase temporarily during a garbage collection which can be an issue in any environment with memory constraints (such as a container). + ### Performance Tuning For tuning the GC performance and the memory footprint, the following options can be used: * `-XX:MaximumHeapSizePercent` - the percentage of the physical memory size that is used as the maximum Java heap size if the maximum Java heap size is not specified otherwise. * `-XX:MaximumYoungGenerationSizePercent` - the maximum size of the young generation as a percentage of the maximum Java heap size. -* `-XX:PercentTimeInIncrementalCollection` - determines how much time the GC should spend doing young collections. -With the default value of 50, the GC tries to balance the time spent on young and full collections. -Increasing this value will reduce the number of full GCs, which can improve performance but may worsen the memory footprint. -Decreasing this value will increase the number of full GCs, which can improve the memory footprint but may decrease performance. * `-XX:±CollectYoungGenerationSeparately` (since GraalVM 21.0) - determines if a full GC collects the young generation separately or together with the old generation. If enabled, this may reduce the memory footprint during full GCs. However, full GCs may take more time. +* `-XX:MaxHeapFree` (since GraalVM 21.3) - maximum total size (in bytes) of free memory chunks that remain reserved for allocations after a collection and are therefore not returned to the operating system. * `-H:AlignedHeapChunkSize` (can only be specified at image build time) - the size of a heap chunk in bytes. -* `-H:MaxSurvivorSpaces` (since GraalVM 21.1, can only be specified at image build time) - the number of survivor spaces that are used for the young generation. +* `-H:MaxSurvivorSpaces` (since GraalVM 21.1, can only be specified at image build time) - the number of survivor spaces that are used for the young generation, that is, the maximum age at which an object will be promoted to the old generation. With a value of 0, objects that survive a young collection are directly promoted to the old generation. * `-H:LargeArrayThreshold` (can only be specified at image build time) - the size at or above which an array will be allocated in its own heap chunk. Arrays that are considered as large are more expensive to allocate but they are never copied by the GC, which can reduce the GC overhead. ```shell -# Build and execute a native image that uses the serial GC but does less full GCs -native-image --gc=serial -R:PercentTimeInIncrementalCollection=70 HelloWorld +# Build and execute a native image that uses a maximum heap size of 25% of the physical memory +native-image --gc=serial -R:MaximumHeapSizePercent=25 HelloWorld ./helloworld -# Execute the native image from above but force more full GCs -./helloworld -XX:PercentTimeInIncrementalCollection=40 +# Execute the native image from above but increase the maximum heap size to 75% of the physical memory +./helloworld -XX:MaximumHeapSizePercent=75 ``` +The following options are available with `-H:InitialCollectionPolicy=BySpaceAndTime` only: + +* `-XX:PercentTimeInIncrementalCollection` - determines how much time the GC should spend doing young collections. + With the default value of 50, the GC tries to balance the time spent on young and full collections. + Increasing this value will reduce the number of full GCs, which can improve performance but may worsen the memory footprint. + Decreasing this value will increase the number of full GCs, which can improve the memory footprint but may decrease performance. + ## G1 Garbage Collector GraalVM Enterprise Edition also provides the Garbage-First (G1) garbage collector, which is based on the G1 GC from the Java HotSpot VM. diff --git a/docs/reference-manual/native-image/NativeImageHeapdumpEnterprise.md b/docs/reference-manual/native-image/NativeImageHeapdumpEnterprise.md index 3cf3f0c9c362..9c89b0cb884f 100644 --- a/docs/reference-manual/native-image/NativeImageHeapdumpEnterprise.md +++ b/docs/reference-manual/native-image/NativeImageHeapdumpEnterprise.md @@ -8,24 +8,20 @@ permalink: /reference-manual/native-image/NativeImageHeapdump/ With GraalVM Enterprise Edition you can generate heap dumps of the Native Image processes to monitor the execution. -Native Image does not implement JVMTI agent and it is not possible to trigger -heap dump creation using tools like _VisualVM_ or _jmap_. You can build a native image for your application in a way so that it can handle certain signals and then get a heap -dump when the application receives the `USR1` signal (other supported signals are `QUIT/BREAK` for stackdumps and `USR2` to dump runtime compilation info). You only need to build your image with GraalVM Enterprise Native Image and use the `-H:+AllowVMInspection` option. +Native Image does not implement JVMTI agent and it is not possible to trigger heap dump creation using tools like _VisualVM_ or _jmap_. +You can build a native image for your application in a way so that it can handle certain signals and then get a heap dump when the application receives the `USR1` signal (other supported signals are `QUIT/BREAK` for stackdumps and `USR2` to dump runtime compilation info). +You only need to build your image with GraalVM Enterprise Native Image and use the `-H:+AllowVMInspection` option. -Another possibility is to -write a special method which will generate a heap dump at certain points in the -lifetime of your application. For example, when certain conditions are met while -executing a native image, your application code can trigger heap dump creation. -A dedicated [`org.graalvm.nativeimage.VMRuntime#dumpHeap`](https://github.com/oracle/graal/blob/master/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VMInspection.java) API exists for this -purpose. Both possibilities are covered in this guide. +Another possibility is to write a special method which will generate a heap dump at certain points in the lifetime of your application. For example, when certain conditions are met while executing a native image, your application code can trigger heap dump creation. +A dedicated [`org.graalvm.nativeimage.VMRuntime#dumpHeap`](https://github.com/oracle/graal/blob/master/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VMInspection.java) API exists for this purpose. +Both possibilities are covered in this guide. Note: This feature is available with **GraalVM Enterprise** only. ## Handle SIGUSR1 Signal -The following Java example is a simple multi-threaded application which runs for -60 seconds. There is enough time to get its PID and send the SIGUSR1 signal -which will generate a heap dump into the application's working directory. Save -the following code as _SVMHeapDump.java_ file on your disk: +The following Java example is a simple multi-threaded application which runs for 60 seconds. +There is enough time to get its PID and send the SIGUSR1 signal which will generate a heap dump into the application's working directory. +Save the following code as _SVMHeapDump.java_ file on your disk: ```java import java.text.DateFormat; import java.util.Date; @@ -81,9 +77,8 @@ $JAVA_HOME/bin/javac SVMHeapDump.java ``` If you run it on `java`, you will see that it runs for 60 seconds then finishes. -Build a native executable and provide the `-H:+AllowVMInspection` option for the -builder. This way the native executable will accept SIGUSR1 signal to produce a -heap dump. +Build a native executable and provide the `-H:+AllowVMInspection` option for the builder. +This way the native executable will accept SIGUSR1 signal to produce a heap dump. ```shell $JAVA_HOME/bin/native-image SVMHeapDump -H:+AllowVMInspection @@ -105,9 +100,8 @@ $JAVA_HOME/bin/native-image SVMHeapDump -H:+AllowVMInspection [svmheapdump:41691] [total]: 47,805.47 ms, 2.62 GB ``` -The `native-image` builder analyzes existing `SVMHeapDump.class` and creates from -it an executable file. When the command completes, `svmheapdump` is created in -the current directory. +The `native-image` builder analyzes existing `SVMHeapDump.class` and creates from it an executable file. +When the command completes, `svmheapdump` is created in the current directory. ##### Run the application and check the heap dump Run the application: @@ -121,10 +115,7 @@ Starting thread! May 15, 2020, 4:28:14 PM: Thread started, it will run for 60 seconds ``` -Open the 2nd terminal to get the process ID of the running `svmheapdump` -application using a command like `ps -C svmheapdump -o pid=` for Linux OS and -`pgrep svmheapdump` for macOS. Copy the printed process ID, e.g. 100, and use it -to send the signal to the running application: +Open the 2nd terminal to get the process ID of the running `svmheapdump` application using a command like `ps -C svmheapdump -o pid=` for Linux OS and `pgrep svmheapdump` for macOS. Copy the printed process ID, e.g. 100, and use it to send the signal to the running application: ```shell kill -SIGUSR1 100 ``` @@ -132,8 +123,7 @@ The heap dump will be available at the working directory while the application c ## Generate a Heap Dump from within a Java Application -The following Java example shows how a heap dump can be generated from within -a running Java application using `VMRuntime.dumpHeap()` after some condition is met. +The following Java example shows how a heap dump can be generated from within a running Java application using `VMRuntime.dumpHeap()` after some condition is met. The condition to generate a heap dump is provided as an option on the command line. Save the code snippet below as _SVMHeapDumpAPI.java_. @@ -186,8 +176,7 @@ public class SVMHeapDumpAPI { } } ``` -The application creates some data to have something to dump, checks the command line -to see if heap dump has to be created, and then in method `createHeapDump()` creates +The application creates some data to have something to dump, checks the command line to see if heap dump has to be created, and then in method `createHeapDump()` creates the actual heap dump, performing checks for file's existence. #### Building a Native Image @@ -219,8 +208,7 @@ $JAVA_HOME/bin/native-image SVMHeapDumpAPI When the command completes, the `svmheapdumpapi` executable is created in the current directory. ##### Run the application and check the heap dump -Now you can run your native image application and generate a heap dump from it -with the output similar to one below: +Now you can run your native image application and generate a heap dump from it with the output similar to one below: ```shell ./svmheapdumpapi --heapdump Sep 15, 2020, 4:06:36 PM: Hello GraalVM native image developer. @@ -228,4 +216,4 @@ Your command line options are: --heapdump Heap dump created /var/folders/hw/s9d78jts67gdc8cfyq5fjcdm0000gp/T/SVMHeapDump-6437252222863577987.hprof, size: 8051959 ``` -The resulting heap dump can be then opened with the [VisualVM](/tools/visualvm/) tool like any other Java heap dump. +The resulting heap dump can be then opened with the [VisualVM](../../tools/visualvm.md) tool like any other Java heap dump. diff --git a/docs/reference-manual/native-image/Options.md b/docs/reference-manual/native-image/Options.md index 63c20d8b84c8..a6b43c6fcc7d 100644 --- a/docs/reference-manual/native-image/Options.md +++ b/docs/reference-manual/native-image/Options.md @@ -6,29 +6,23 @@ permalink: /reference-manual/native-image/Options/ --- # Native Image Options -The `native-image` builder needs to provide the classpath for all classes -using the familiar option from the `java` launcher: `-cp` is followed by a list -of directories or JAR files, separated by `:`. The name of the class containing -the `main` method is the last argument, or you can use `-jar` and provide a JAR -file that specifies the main method in its manifest. +The `native-image` builder needs to provide the classpath for all classes using the familiar option from the `java` launcher: `-cp` is followed by a list of directories or JAR files, separated by `:`. +The name of the class containing the `main` method is the last argument, or you can use `-jar` and provide a JAR file that specifies the main method in its manifest. The syntax of the `native-image` command is: -- `native-image [options] class [imagename] [options]` to build an executable file for a class in the -current working directory. Invoking it executes the native-compiled code of that +- `native-image [options] class [imagename] [options]` to build an executable file for a class in the current working directory. Invoking it executes the native-compiled code of that class. - `native-image [options] -jar jarfile [imagename] [options]` to build an image for a JAR file. The options passed to `native-image` are evaluated left-to-right. For more information, see [Native Image Build Configuration](BuildConfiguration.md#order-of-arguments-evaluation). -The options fall into four categories: -image generation options, macro options, non-standard options, and server options. +The options fall into four categories: image generation options, macro options, non-standard options, and server options. Non-standard and server options are subject to change through a deprecation cycle. -Command-line help is available. Run `native-image --help` to get -the commands overview, and `native-image --help-extra` to print help on non-standard, -macro, and server options. +Command-line help is available. +Run `native-image --help` to get the commands overview, and `native-image --help-extra` to print help on non-standard, macro, and server options. ### Options to Native Image Builder @@ -94,7 +88,7 @@ instantiation is traced for. * `--tool:lsp`: add the Language Server Protocol support to later attach compatible debuggers to GraalVM in IDEs like VS Code * `--tool:profiler`: add profiling support to a GraalVM supported language -The `--language:python`, `--language:ruby` and `--language:R` polyglot macro options become available once the corresponding languages are added to the base GraalVM installation (see the [GraalVM Updater](https://www.graalvm.org/reference-manual/graalvm-updater/) guide). +The `--language:python`, `--language:ruby` and `--language:R` polyglot macro options become available once the corresponding languages are added to the base GraalVM installation (see the [GraalVM Updater](../graalvm-updater.md) guide). ### Non-standard Options * `--expert-options`: list image build options for experts diff --git a/docs/reference-manual/native-image/README.md b/docs/reference-manual/native-image/README.md index f54ac4b42196..446d5cb15345 100644 --- a/docs/reference-manual/native-image/README.md +++ b/docs/reference-manual/native-image/README.md @@ -18,11 +18,9 @@ Then it ahead-of-time compiles that reachable code and data to a native executab This entire process is called **building an image** (or the **image build time**) to clearly distinguish it from the compilation of Java source code to bytecode. Native Image supports JVM-based languages, e.g., Java, Scala, Clojure, Kotlin. -The resulting image can, optionally, execute dynamic languages like -JavaScript, Ruby, R or Python. Polyglot embeddings can also be compiled -ahead-of-time. To inform `native-image` of a guest language used by an -application, specify `--language:` for each guest language (e.g., -`--language:js`). +The resulting image can, optionally, execute dynamic languages like JavaScript, Ruby, R or Python. +Polyglot embeddings can also be compiled ahead-of-time. +To inform `native-image` of a guest language used by an application, specify `--language:` for each guest language (e.g., `--language:js`). * [Install Native Image](#install-native-image) * [Prerequisites](#prerequisites) @@ -42,23 +40,21 @@ For more information, check the [Oracle Technology Network License Agreement for ## Install Native Image -Native Image can be added to GraalVM with the [GraalVM Updater](https://www.graalvm.org/reference-manual/graalvm-updater/) tool. +Native Image can be added to GraalVM with the [GraalVM Updater](../graalvm-updater.md) tool. Run this command to install Native Image: ```shell gu install native-image ``` After this additional step, the `native-image` executable will become available in -the `GRAALVM_HOME/bin` directory. +the `$JAVA_HOME/bin` directory. The above command will install Native Image from the GitHub catalog for GraalVM Community users. -For GraalVM Enterprise users, the [manual installation](https://www.graalvm.org/reference-manual/graalvm-updater/#manual-installation) is required. +For GraalVM Enterprise users, the [manual installation](../graalvm-updater.md#manual-installation) is required. ## Prerequisites -For compilation `native-image` depends on the local toolchain. Install - `glibc-devel`, `zlib-devel` (header files for the C library and `zlib`) -and `gcc`, using a package manager available on your OS. Some Linux distributions may additionally require `libstdc++-static`. +For compilation `native-image` depends on the local toolchain. Install `glibc-devel`, `zlib-devel` (header files for the C library and `zlib`) and `gcc`, using a package manager available on your OS. Some Linux distributions may additionally require `libstdc++-static`. On Oracle Linux use `yum` package manager: ```shell @@ -80,10 +76,16 @@ xcode-select --install ``` #### Prerequisites for Using Native Image on Windows -Building native images on Windows requires a Microsoft Visual C++ (MSVC) that comes with Visual Studio 2017 15.5.5 or later. -In addition, a proper [Developer Command Prompt](https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=vs-2019#developer_command_prompt_shortcuts) for your version of [Visual Studio](https://visualstudio.microsoft.com/vs/). -On Windows the `native-image` tool only works when it is executed from the **x64 Native Tools Command Prompt**. +To start using Native Image on Windows, install [Visual Studio](https://visualstudio.microsoft.com/vs/) and Microsoft Visual C++(MSVC). There are two installation options: + * Install the Visual Studio Code Build Tools with the Windows 10 SDK + * Install Visual Studio Code with the Windows 10 SDK + +You can use Visual Studio 2017 version 15.9 or later. + +Lastly, on Windows, the `native-image` builder will only work when it is executed from the **x64 Native Tools Command Prompt**. +The command for initiating an x64 Native Tools command prompt is different if you only have the Visual Studio Build Tools installed, versus if you have the full VS Code 2019 installed. +Check [this link](https://medium.com/graalvm/using-graalvm-and-native-image-on-windows-10-9954dc071311) for step-by-step instructions. ## Build a Native Image @@ -105,12 +107,9 @@ To build a native image of a JAR file, use: native-image [options] -jar jarfile [imagename] [options] ``` -The `native-image` command needs to provide the class path for all classes using -the familiar option from the java launcher: `-cp` followed by a list of +The `native-image` command needs to provide the class path for all classes using the familiar option from the java launcher: `-cp` followed by a list of directories or JAR files, separated by `:` on Linux and macOS platforms, or `;` on Windows. -The name of the class containing the -main method is the last argument, or you can use `-jar` and provide a JAR -file that specifies the main method in its manifest. +The name of the class containing the main method is the last argument, or you can use `-jar` and provide a JAR file that specifies the main method in its manifest. As an example, take this small Java program that reverses a String using recursion: ```java @@ -134,20 +133,18 @@ Compile it and build a native image from the Java class: javac Example.java native-image Example ``` -The native image builder ahead-of-time compiles the `Example` class into a -standalone executable, `example`, in the current working directory. Run the executable: +The native image builder ahead-of-time compiles the `Example` class into a standalone executable, `example`, in the current working directory. +Run the executable: ```shell ./example ``` -Another option to the native image builder that might be helpful is -`--install-exit-handlers`. It is not recommended to register the default signal -handlers when building a shared library. However, it is desirable to include -signal handlers when building a native image for containerized environments, like -Docker containers. The `--install-exit-handlers` option gives you the same -signal handlers that a JVM does. +Another option to the native image builder that might be helpful is `--install-exit-handlers`. +It is not recommended to register the default signal handlers when building a shared library. +However, it is desirable to include signal handlers when building a native image for containerized environments, like Docker containers. +The `--install-exit-handlers` option gives you the same signal handlers that a JVM does. -For more complex examples, visit the [native image generation](https://www.graalvm.org/examples/native-image-examples/) or [compiling a Java and Kotlin app ahead-of-time](https://www.graalvm.org/examples/java-kotlin-aot/) pages. +For more complex examples, visit the [native image generation](../../examples/native-image-examples.md) or [compiling a Java and Kotlin app ahead-of-time](../../examples/java-kotlin-aot.md) pages. ## Build a Shared Library @@ -165,7 +162,9 @@ Note: if you build a shared library where you do not specify a main class, you m As mentioned in the previous section, you need to have at least one entry point method for a native image to be useful. For shared libraries, Native Image provides the `@CEntryPoint` annotation to specify entry point methods that should be exported and callable from C. -Entry point methods must be static and may only have non-object parameters and return types – this includes Java primitives, but also Word types (including pointers). One of the parameters of an entry point method has to be of type `IsolateThread` or `Isolate`. This parameter provides the current thread's execution context for the call. +Entry point methods must be static and may only have non-object parameters and return types – this includes Java primitives, but also Word types (including pointers). +One of the parameters of an entry point method has to be of type `IsolateThread` or `Isolate`. +This parameter provides the current thread's execution context for the call. For example: @@ -176,7 +175,8 @@ For example: ``` When building a shared library, an additional C header file is generated. -This header file contains declarations for the [C API](C-API.md), which allows creating isolates and attaching threads from C code, as well as declarations for each entry point in the source code. The generated C declaration for the above example is: +This header file contains declarations for the [C API](C-API.md), which allows creating isolates and attaching threads from C code, as well as declarations for each entry point in the source code. +The generated C declaration for the above example is: ```c int add(graal_isolatethread_t* thread, int a, int b); ``` @@ -192,9 +192,9 @@ native-image -cp hello EmptyHello ... ``` -If you do not know what GraalVM distribution is set to the `PATH` environment -variable, how to determine if a native image was compiled with Community or -Enterprise Edition? Run this command: +If you do not know what GraalVM distribution is set to the `PATH` environment variable, how to determine if a native image was compiled with Community or +Enterprise Edition? +Run this command: ```shell strings emptyhello | grep com.oracle.svm.core.VM ``` @@ -229,10 +229,7 @@ com.oracle.svm.core.VM=GraalVM Java 11 EE ## Ahead-of-time Compilation Limitations -There is a small portion of Java features are not susceptible to ahead-of-time -compilation, and will therefore miss out on the performance advantages. To be -able to build a highly optimized native executable, GraalVM runs an aggressive static -analysis that requires a closed-world assumption, which means that all classes -and all bytecodes that are reachable at run time must be known at build time. -Therefore, it is not possible to load new data that have not been available -during ahead-of-time compilation. Continue reading to [GraalVM Native Image Compatibility and Optimization](Limitations.md). +There is a small portion of Java features are not susceptible to ahead-of-time compilation, and will therefore miss out on the performance advantages. +To be able to build a highly optimized native executable, GraalVM runs an aggressive static analysis that requires a closed-world assumption, which means that all classes and all bytecodes that are reachable at run time must be known at build time. +Therefore, it is not possible to load new data that have not been available during ahead-of-time compilation. +Continue reading to [GraalVM Native Image Compatibility and Optimization](Limitations.md). diff --git a/docs/reference-manual/native-image/Reflection.md b/docs/reference-manual/native-image/Reflection.md index 483653e2b70e..dbd09af22744 100644 --- a/docs/reference-manual/native-image/Reflection.md +++ b/docs/reference-manual/native-image/Reflection.md @@ -4,6 +4,12 @@ toc_group: native-image link_title: Reflection on Native Image permalink: /reference-manual/native-image/Reflection/ --- + +* [Automatic Detection](#automatic-detection) +* [Manual Configuration](#manual-configuration) +* [Conditional Configuration](#conditional-configuration) +* [Configuration with Features](#configuration-with-features) + # Reflection Use in Native Images Java reflection support (the `java.lang.reflect.*` API) enables Java code to examine its own classes, methods, fields and their properties at run time. @@ -128,7 +134,9 @@ Also, `-H:ReflectionConfigurationResources` can be specified to load one or seve ### Conditional Configuration -With conditional configuraiton, a class configuration entry is applied only if a provided `condition` is satisfied. The only currently supported condition is `typeReachable`, which enables the configuration entry if the specified type is reachable through other code. For example, to support reflective access to `sun.misc.Unsafe.theUnsafe` only when `io.netty.util.internal.PlatformDependent0` is reachable, the configuration should look like: +With conditional configuration, a class configuration entry is applied only if a provided `condition` is satisfied. +The only currently supported condition is `typeReachable`, which enables the configuration entry if the specified type is reachable through other code. +For example, to support reflective access to `sun.misc.Unsafe.theUnsafe` only when `io.netty.util.internal.PlatformDependent0` is reachable, the configuration should look like: ```json { @@ -140,11 +148,14 @@ With conditional configuraiton, a class configuration entry is applied only if a } ``` -Conditional configuration is the *preferred* way to specify reflection configuration: if code doing a reflective access is not reachable, it is unnecessary to include its corresponding reflection entry. The consistent usage of `condition` results in *smaller binaries* and *better build times* as the image builder can selectively include reflectively accessed code. +Conditional configuration is the **preferred** way to specify reflection configuration: if code doing a reflective access is not reachable, it is unnecessary to include its corresponding reflection entry. +The consistent usage of `condition` results in *smaller binaries* and *better build times* as the image builder can selectively include reflectively accessed code. -If a `condition` is omitted, the element is always included. When the same `condition` is used for two distinct elements in two configuration entries, both elements will be included when the condition is satisfied. When a configuration entry should be enabled if one of several types are reachable, it is necessary to add two configuration entries: one entry for each condition. +If a `condition` is omitted, the element is always included. +When the same `condition` is used for two distinct elements in two configuration entries, both elements will be included when the condition is satisfied. +When a configuration entry should be enabled if one of several types are reachable, it is necessary to add two configuration entries: one entry for each condition. -When used with [assisted configuration](BuildConfiguration.md#assisted-configuration-of-native-image-builds), conditional entries of existing configuration will not be fused with agent-collected entries as agent-collected entries. +When used with [assisted configuration](BuildConfiguration.md#assisted-configuration-of-native-image-builds), conditional entries of existing configuration will not be fused with agent-collected entries. ### Configuration with Features @@ -165,11 +176,14 @@ class RuntimeReflectionRegistrationFeature implements Feature { } } ``` -To activate the custom feature `--features=` needs to be passed to native-image. [Native Image Build Configuration](BuildConfiguration.md) explains how this can be automated with a `native-image.properties` file in `META-INF/native-image`. +To activate the custom feature `--features=` needs to be passed to native-image. +[Native Image Build Configuration](BuildConfiguration.md) explains how this can be automated with a `native-image.properties` file in `META-INF/native-image`. ### Use of Reflection during Native Image Generation Reflection can be used without restrictions during a native image generation, for example, in static initializers. At this point, code can collect information about methods and fields and store them in their own data structures, which are then reflection-free at run time. ### Unsafe Accesses -The `Unsafe` class, although its use is discouraged, provides direct access to the memory of Java objects. The `Unsafe.objectFieldOffset()` method provides the offset of a field within a Java object. Note that the offsets that are queried during native image generation can be different from the offsets at run time. +The `Unsafe` class, although its use is discouraged, provides direct access to the memory of Java objects. +The `Unsafe.objectFieldOffset()` method provides the offset of a field within a Java object. +Note that the offsets that are queried during native image generation can be different from the offsets at run time. diff --git a/docs/reference-manual/native-image/Reports.md b/docs/reference-manual/native-image/Reports.md index ee2e5e8dca11..1b518cdabfdc 100644 --- a/docs/reference-manual/native-image/Reports.md +++ b/docs/reference-manual/native-image/Reports.md @@ -6,12 +6,9 @@ permalink: /reference-manual/native-image/Reports/ --- # Points-to Analysis Reports -The points-to analysis produces two kinds of reports: analysis call tree and -image object tree. This information is produced by an intermediate step in the -image building process and represents the static analysis view of the call graph -and heap object graph. These graphs are further transformed in the image -building process before they are AOT compiled into the image and written into -the image heap, respectively. +The points-to analysis produces two kinds of reports: analysis call tree and image object tree. +This information is produced by an intermediate step in the image building process and represents the static analysis view of the call graph and heap object graph. +These graphs are further transformed in the image building process before they are AOT compiled into the image and written into the image heap, respectively. #### Call tree The call tree is a a breadth-first tree reduction of the call graph as seen by the points-to analysis. @@ -151,3 +148,16 @@ The call tree report name has the structure `call_tree__. The object tree report name has the structure: `object_tree__.txt`. The image name is the name of the generated image, which can be set with the `-H:Name=` option. The `` is in the `yyyyMMdd_HHmmss` format. + +#### CSV files + +The reports include a number of CSV files containing raw data for methods and their relationships. +The aim of these files is to make it enable this raw data to be easily imported into graph databases. +Graph databases can provide the following functionality: + +* Sophisticated graphical visualization of the call tree graph that provide a different perspective compared to text-based formats. +* Ability to execute complex queries that can for example show a subset of the tree that causes certain code path to be included in the call tree analysis. +This querying functionality is crucial in making big analysis call trees manageable. + +The process to import the files into graph databases is specific to each database. +Please follow the instructions provided by the graph database providers to find out how to import them. diff --git a/docs/reference-manual/native-image/Resources.md b/docs/reference-manual/native-image/Resources.md index 3c12fe49671f..e1aa1e5d8b72 100644 --- a/docs/reference-manual/native-image/Resources.md +++ b/docs/reference-manual/native-image/Resources.md @@ -26,7 +26,9 @@ To make calls such as `Class.getResource()` or `Class.getResourceAsStream()` (or } ``` -The configuration file's path must be provided to `native-image` with `-H:ResourceConfigurationFiles=/path/to/resource-config.json`. Alternatively, individual resource paths can also be specified directly to `native-image`: +The configuration file's path must be provided to `native-image` with `-H:ResourceConfigurationFiles=/path/to/resource-config.json`. +Alternatively, individual resource paths can also be specified directly to `native-image`: + ```shell native-image -H:IncludeResources= -H:ExcludeResources= ... ``` @@ -60,9 +62,8 @@ See also the [guide on assisted configuration of Java resources and other dynami ## Locales -It is also possible to specify which locales should be included in the image and what should be the default one. For -example, to switch the default locale to German and also include French and English, one can use the following hosted -options. +It is also possible to specify which locales should be included in the image and what should be the default one. +For example, to switch the default locale to German and also include French and English, one can use the following hosted options. ```shell native-image -H:DefaultLocale=de -H:IncludeLocales=fr,en ``` @@ -74,7 +75,8 @@ binary. Java localization support (`java.util.ResourceBundle`) enables Java code to load L10N resources and show the right user messages suitable for actual runtime settings like time locale and format, etc. -Native Image needs ahead-of-time knowledge of the resource bundles your application needs so that it can load and store the appropriate bundles for usage in the generated binary. The bundles can be specified in the resource configuration file (see above), in the `bundles` section: +Native Image needs ahead-of-time knowledge of the resource bundles your application needs so that it can load and store the appropriate bundles for usage in the generated binary. +The bundles can be specified in the resource configuration file (see above), in the `bundles` section: ```json { @@ -91,13 +93,12 @@ Alternatively, bundles can be specified directly as options to `native-image` as ```shell native-image -H:IncludeResourceBundles=your.pgk.Bundle,another.pkg.Resource,etc.Bundle ... ``` -By default, the requested bundles are included for all requested locales. In order to optimize this, it is possible to -use ``IncludeResourceBundles`` with locale specific substring, for -example ``-H:+IncludeResourceBundles=com.company.bundles.MyBundle_fr-FR`` will include the bundle only in French. +By default, the requested bundles are included for all requested locales. +In order to optimize this, it is possible to use ``IncludeResourceBundles`` with locale specific substring, for example ``-H:+IncludeResourceBundles=com.company.bundles.MyBundle_fr-FR`` will include the bundle only in French. ### JVM Mode of Localization -Resource Bundle lookup is a complex and dynamic mechanism which utilizes a lot of the infrastructure of JVM. As a result of that, it causes image size increase -for smaller applications such as Hello World. Therefore, an optimized mode is set by default in which this lookup is simplified utilizing the fact the all -bundles are known ahead of time. +Resource Bundle lookup is a complex and dynamic mechanism which utilizes a lot of the infrastructure of JVM. +As a result of that, it causes image size increase for smaller applications such as Hello World. +Therefore, an optimized mode is set by default in which this lookup is simplified utilizing the fact the all bundles are known ahead of time. In case you would like to use the original JVM lookup, use the `-H:-LocalizationOptimizedMode` option. diff --git a/docs/reference-manual/native-image/StaticImages.md b/docs/reference-manual/native-image/StaticImages.md index 73bfbb34e228..cb3985df24d2 100644 --- a/docs/reference-manual/native-image/StaticImages.md +++ b/docs/reference-manual/native-image/StaticImages.md @@ -4,58 +4,76 @@ toc_group: native-image link_title: Static Native Images permalink: /reference-manual/native-image/StaticImages/ --- -# Static Native Images +# Static and Mostly Static Images -Static native images are statically linked binaries which can be used without any additional library dependencies. -This makes them suitable for use in a Docker container. +With GraalVM Native Image you can create static or mostly static images, depending on the purposes. + +**Static native images** are statically linked binaries which can be used without any additional library dependencies. +This makes them easier to distribute and to deploy on slim or distroless container images. +They are created by statically linking against [musl-libc](https://musl.libc.org/), a lightweight, fast and simple `libc` implementation. + +**Mostly static native images** statically link against all libraries except `libc`. +This approach is ideal for deploying such native images on distroless container images. +Note that it currently only works when linking against `glibc`. ## Prerequisites - - Right now, this only works on Linux AMD64 on Java 11. - - You will need `gcc`, `make`, and `configure`. - - Create a directory that will hold the libraries you build. You will refer to this directory as `${RESULT_DIR}`. - - Download the latest `musl` release [here](https://musl.libc.org/). This document will use `musl-1.2.0`. - - Download the latest `zlib` release [here](https://zlib.net/). This document will use `zlib-1.2.11`. - ## Build a Static Native Image +- Linux AMD64 operating system +- GraalVM distribution for Java 11 with [Native Image support](README.md#install-native-image) +- A 64-bit `musl` toolchain, `make`, and `configure` +- The latest `zlib` library -If you have `musl-gcc` on the path, you can build a native image statically linked against `muslc` with the following options: `--static --libc=musl`. -To verify that `musl-gcc` is on the path, run `musl-gcc -v`. +## Preparation -To build a static native image, use: -```shell -native-image --static --libc=musl [other arguments] Class -``` +You should get the `musl` toolchain first, and then compile and install `zlib` into the toolchain. + +1. Download the `musl` toolchain from [musl.cc](https://musl.cc/). [This one](http://musl.cc/x86_64-linux-musl-native.tgz) is recommended. Extract the toolchain to a directory of your choice. This directory will be referred as `$TOOLCHAIN_DIR`. +2. Download the latest `zlib` library sources from [here](https://zlib.net/) and extract them. This guide uses `zlib-1.2.11`. +3. Set the following environment variable: + ```bash + CC=$TOOLCHAIN_DIR/bin/gcc + ``` +4. Change into the `zlib` directory, and then run the following commands to compile and install `zlib` into the toolchain: + ```bash + ./configure --prefix=$TOOLCHAIN_DIR --static + make + make install + ``` + +## Build Static Native Image -## Build a Mostly Static Native Image +1. First, ensure `$TOOLCHAIN_DIR/bin` is present on your `PATH` variable. + To verify this, run: + ```bash + x86_64-linux-musl-gcc + ``` + You should get a similar output printed: + ```bash + x86_64-linux-musl-gcc: fatal error: no input files + compilation terminated. + ``` -As of GraalVM version 20.2, you can build a “mostly static” native image which link statically everything except `libc`. Native images built this way are convenient to run in Docker containers, for example, based on -[distroless minimal Linux, glibc-based systems](https://github.com/GoogleContainerTools/distroless/blob/master/base/README.md). +2. Build a static native image by using this command: + ```shell + native-image --static --libc=musl [other arguments] Class + ``` -To build a mostly-static native image native image, use: +## Build Mostly Static Native Image + +As of GraalVM version 20.2, you can build a “mostly static” native image which statically links everything except `libc`. +Statically linking all your libraries except `glibc` ensures your application has all the libraries it needs to run on any Linux `glibc`-based distribution. + +To build a mostly-static native image native image, use this command: ```shell native-image -H:+StaticExecutableWithDynamicLibC [other arguments] Class ``` -#### Building musl - - Extract the musl release `tarball` and `cd` into the extracted directory. - - Run `./configure --disable-shared --prefix=${RESULT_DIR}`. - - Run `make`. - - Run `make install`. -Other than building `musl` libraries, the build also creates a `gcc` wrapper called `musl-gcc` in the `${RESULT_DIR}/bin` directory. -You should now put this wrapper on your `PATH` by running `export PATH=$PATH:${RESULT_DIR}/bin`. - -#### Building zlib - - Extract the zlib release `tarball` and `cd` into the extracted directory. - - You need to compile zlib and link it against musl so set `CC` to `musl-gcc`: `export CC=musl-gcc`. - - Run `./configure --static --prefix=${RESULT_DIR}`. - - Run `make`. - - Run `make install`. - -#### Getting libstdc++ -`libstdc++` is obtained by building gcc. There are multiple approaches to obtaining it: - 1. Build gcc with `musl-gcc`. - 2. Use `libstdc++.a` from your distribution. If you choose this path, check the [FAQs](https://www.musl-libc.org/faq.html) page, "How do I use the musl-gcc wrapper?": - > The existing libstdc++ is actually compatible with musl in most cases and could be used by copying it into the musl library path, but the C++ header files are usually not compatible. - > Since you do not need C++ header files, this approach should work. If you run into issues, make sure they are not caused by your ditribution's `libstdc++.a`. - 3. Take `libstdc++.a` from Alpine. -In each case, `libstdc++.a` must be placed in `${RESULT_DIR}/lib`. +> Note: This currently only works for `glibc`. + +## Frequently Asked Questions + +### What is the recommended base Docker image for deploying a static or mostly static native image? + +A fully static native image gives you the most flexibility to choose a base image - it can run on anything including a `FROM scratch` image. +A mostly static native image requires a container image that provides `glibc`, but has no additional requirements. +In both cases, choosing the base image mostly depends on what your particular native image needs without having to worry about run-time library dependencies. diff --git a/docs/reference-manual/polyglot-programming.md b/docs/reference-manual/polyglot-programming.md index fb8074f062cc..1d4bb3455a75 100644 --- a/docs/reference-manual/polyglot-programming.md +++ b/docs/reference-manual/polyglot-programming.md @@ -14,20 +14,17 @@ permalink: /reference-manual/polyglot-programming/ * [Passing Options Programmatically](#passing-options-programmatically) * [Passing Options Using JVM Arguments](#passing-options-using-jvm-arguments) -GraalVM allows users to write polyglot applications that seamlessly -pass values from one language to another by means of the [Truffle language implementation framework](/graalvm-as-a-platform/language-implementation-framework/) (henceforth "Truffle"). +GraalVM allows users to write polyglot applications that seamlessly pass values from one language to another by means of the [Truffle language implementation framework](../../truffle/docs/README.md) (henceforth "Truffle"). Truffle is a Java library for building programming languages implementations as interpreters for self-modifying Abstract Syntax Trees. When writing a language interpreter with Truffle, it will automatically use the GraalVM compiler as a just-in-time compiler for the language. By having access to this framework, a Ruby application, for example, can run on the same JVM as a Java application. Also, a host JVM-based language and a guest language can directly interoperate with each other and pass data back and forth in the same memory space. -In order to provide foreign polyglot values in the languages implemented with Truffle, the so-called _polyglot interoperability protocol_ has been developed. This -interoperability protocol consists of a set of standardized messages that every -language implements and uses for foreign polyglot values. The protocol allows -GraalVM to support interoperability between any combination of languages without -requiring them to know of each other. For more details, proceed to the -[High-Performance Cross-Language Interoperability in a Multi-Language Runtime](http://dx.doi.org/10.1145/2816707.2816714) paper. +In order to provide foreign polyglot values in the languages implemented with Truffle, the so-called _polyglot interoperability protocol_ has been developed. +This interoperability protocol consists of a set of standardized messages that every language implements and uses for foreign polyglot values. +The protocol allows GraalVM to support interoperability between any combination of languages without requiring them to know of each other. +For more details, proceed to the [High-Performance Cross-Language Interoperability in a Multi-Language Runtime](http://dx.doi.org/10.1145/2816707.2816714) paper. Throughout this section you learn how to combine multiple languages using GraalVM Polyglot APIs. @@ -41,15 +38,12 @@ Ensure you set up GraalVM before you begin. The below examples work: * on a JVM, by passing `--polyglot --jvm`. * on native launchers with `--polyglot` (e.g., `js --polyglot`). - It might be required to [rebuild images](/reference-manual/graalvm-updater/#rebuild-images) to access languages installed with `gu`. + It might be required to [rebuild images](graalvm-updater.md#rebuild-images) to access languages installed with `gu`. * with native executables (e.g., `native-image --language:js`). -For native launchers and native executables using Java as a Target Language -and accessing classes other than Java arrays, it is required to recompile the image and provide -a [reflection configuration file](/reference-manual/native-image/Reflection/). +For native launchers and native executables using Java as a Target Language and accessing classes other than Java arrays, it is required to recompile the image and provide a [reflection configuration file](native-image/Reflection.md). -Note: To start an application with LLVM as a Target Language, make sure -to precompile the _polyglot.c_ file provided below. +Note: To start an application with LLVM as a Target Language, make sure to precompile the _polyglot.c_ file provided below. ### Start from JavaScript / Node.js @@ -134,7 +128,6 @@ graalpython --polyglot --jvm polyglot.py 42 ``` - ### Start Language Java Create the file `Polyglot.java`: @@ -169,9 +162,8 @@ tab4type="c" tab4id="c_to_python" tab4name="Python" tab4path="polyglot_ref/c_to_ tab5type="c" tab5id="c_to_java" tab5name="Java" tab5path="polyglot_ref/c_to_java.c" %} -The example C code has to be compiled to LLVM bitcode using the LLVM frontend -such as `clang`. A user can use `clang` shipped with GraalVM by installing a -pre-built LLVM toolchain support: +The example C code has to be compiled to LLVM bitcode using the LLVM frontend such as `clang`. +A user can use `clang` shipped with GraalVM by installing a pre-built LLVM toolchain support: ```shell gu install llvm-toolchain @@ -187,12 +179,10 @@ lli --polyglot polyglot ## Polyglot Launcher -With polyglot applications it is often impossible to decide what the primary -language of an application is. Therefore, an experimental new -launcher, called `polyglot`, has been added to GraalVM. For the moment, this launcher runs code -for JavaScript, Ruby, and R without requiring the selection of a primary -language. The polyglot launcher does not require the `--polyglot` option; it is -enabled by default. +With polyglot applications it is often impossible to decide what the primary language of an application is. +Therefore, an experimental new launcher, called `polyglot`, has been added to GraalVM. +For the moment, this launcher runs code for JavaScript, Ruby, and R without requiring the selection of a primary language. +The polyglot launcher does not require the `--polyglot` option; it is enabled by default. This is how you can run a polyglot application by using the examples from above: @@ -201,7 +191,7 @@ polyglot --jvm polyglot.js polyglot.R polyglot.rb ``` We have also included a basic experimental shell for multiple languages called the _Polyglot Shell_. -It is useful to quickly test the interactivity of languages implemented with the [Truffle framework](/graalvm-as-a-platform/language-implementation-framework/). +It is useful to quickly test the interactivity of languages implemented with the [Truffle framework](../../truffle/docs/README.md). This is how you can start it: ```shell @@ -210,20 +200,20 @@ polyglot --jvm --shell If you have installed all optional languages packs to the core GraalVM installation, then the Polyglot Shell will look like: ```shell -GraalVM MultiLanguage Shell 21.2.0 +GraalVM MultiLanguage Shell 21.3.0 Copyright (c) 2013-2021, Oracle and/or its affiliates Java version 1.8|11 -JavaScript version 21.2.0 +JavaScript version 21.3.0 Python version 3.8.5 R version 4.0.3 -Ruby version 2.7.3 +Ruby version 2.7.4 Usage: - Use Ctrl+n to switch language and Ctrl+d to exit. + Use Ctrl+n to switch language and Ctrl+d to exit. Enter -usage to get a list of available commands. js> ``` -Note: The `polyglot` launcher and the _Polyglot Shell_ are experimental features in GraalVM. +> Note: The `polyglot` launcher and the _Polyglot Shell_ are experimental features in GraalVM. ## Polyglot Options @@ -243,8 +233,7 @@ You can configure a language engine for better throughput or startup. ## Passing Options for Language Launchers Every language launcher has been extended with a set of so called _polyglot options_. -Polyglot options allow users of any language launcher to access the -options of other languages supported by GraalVM (implemented with the Truffle language implementation framework). +Polyglot options allow users of any language launcher to access the options of other languages supported by GraalVM (implemented with the Truffle language implementation framework). The format is: `--.=`. For example, the `R` launcher also supports the `--js.atomics=true` JavaScript option. @@ -294,8 +283,7 @@ javac OptionsTest.java java OptionsTest ``` -Note: Tools options can be passed in the same way. -Options cannot be modified after the context was created. +> Note: Tools options can be passed in the same way. Options cannot be modified after the context was created. ## Passing Options Using JVM Arguments @@ -327,4 +315,4 @@ javac SystemPropertiesTest.java java -Dpolyglot.js.strict=true SystemPropertiesTest ``` -Note: System properties are read once when the polyglot context is created. Subsequent changes have no effect. +> Note: System properties are read once when the polyglot context is created. Subsequent changes have no effect. diff --git a/docs/reference-manual/reference-manuals.md b/docs/reference-manual/reference-manuals.md index 969593093a0d..3c1e33cd879d 100644 --- a/docs/reference-manual/reference-manuals.md +++ b/docs/reference-manual/reference-manuals.md @@ -14,25 +14,25 @@ environment for their workloads. ## Technologies -[Native Image](/reference-manual/native-image/) - learn in detail about Native Image: GraalVM's innovative technology that can ahead-of-time compile Java code to a self-contained native executable. +[Native Image](native-image/README.md) - learn in detail about Native Image: GraalVM's innovative technology that can ahead-of-time compile Java code to a self-contained native executable. -[Compiler](/reference-manual/compiler/) - learn about the uniqueness of the GraalVM compiler and its advantages. +[Compiler](compiler.md) - learn about the uniqueness of the GraalVM compiler and its advantages. -[Updater](/reference-manual/graalvm-updater/) - learn how to add more capabilities and upgrade the core GraalVM installation. +[Updater](graalvm-updater.md) - learn how to add more capabilities and upgrade the core GraalVM installation. -[Polyglot Programming](/reference-manual/polyglot-programming/) - learn how to write polyglot applications and allow languages to directly interoperate with each other in the same memory space. +[Polyglot Programming](polyglot-programming.md) - learn how to write polyglot applications and allow languages to directly interoperate with each other in the same memory space. -[Embedding Languages](/reference-manual/embed-languages/) - learn how to embed polyglot applications in Java host applications or native images. +[Embedding Languages](embedding/embed-languages.md) - learn how to embed polyglot applications in Java host applications or native images. ## Specific Languages If you are mostly interested in the GraalVM support for a specific language, here you can find the most extensive documentation: -* [Java](/reference-manual/java/) -* [Java on Truffle](/reference-manual/java-on-truffle/) -* [JavaScript and Node.js](/reference-manual/js/) -* [LLVM Languages](/reference-manual/llvm/) -* [Python](/reference-manual/python/) -* [R](/reference-manual/r/) -* [Ruby](/reference-manual/ruby/) -* [WebAssembly](/reference-manual/wasm/) +* [Java](java/README.md) +* [Java on Truffle](java-on-truffle/README.md) +* [JavaScript and Node.js](js/README.md) +* [LLVM Languages](llvm/README.md) +* [Python](python/README.md) +* [R](r/README.md) +* [Ruby](ruby/README.md) +* [WebAssembly](wasm/README.md) diff --git a/docs/reference-manual/wasm/README.md b/docs/reference-manual/wasm/README.md index 4c47f89a120d..66b106f68f37 100644 --- a/docs/reference-manual/wasm/README.md +++ b/docs/reference-manual/wasm/README.md @@ -13,12 +13,12 @@ The support for WebAssembly is in the early stages of its development. ## Installing Wasm -The support is not available by default, but you can add it to GraalVM using the [GraalVM Updater](/reference-manual/graalvm-updater/) tool: +The support is not available by default, but you can add it to GraalVM using the [GraalVM Updater](../graalvm-updater.md) tool: ```shell gu install wasm ``` The above command will install a community version of a component from the GitHub catalog. -For GraalVM Enterprise users, the [manual component installation](/reference-manual/graalvm-updater/#component-installation) is required. +For GraalVM Enterprise users, the [manual component installation](../graalvm-updater.md#component-installation) is required. Then `wasm` launcher, which can run compiled WebAssembly binary code, becomes available. @@ -75,4 +75,4 @@ Value mainFunction = context.getBindings("wasm").getMember("main").getMember("_s mainFunction.execute(); ``` -For more polyglot examples, visit the [Polyglot Programming](/reference-manual/polyglot-programming/) page. +For more polyglot examples, visit the [Polyglot Programming](../polyglot-programming.md) page. diff --git a/docs/security/security-guide.md b/docs/security/security-guide.md index a1b65bd0b2c0..3d4f12fe4593 100644 --- a/docs/security/security-guide.md +++ b/docs/security/security-guide.md @@ -109,14 +109,9 @@ This can either result in sensitive data ending up in the snapshot or fixing ini Developers can request static initializers that process sensitive information to be instead executed at runtime by either specifying the `--initialize-at-run-time` CLI parameter when building a native image, or making use of the `RuntimeClassInitialization` API. -Native-image provides multiple ways to specify the certificate file used to -define the default TrustStore. While the default behavior for native-image is -to capture and use the default TrustStore from the buildtime host environment, -this can be changed at runtime by setting the "javax.net.ssl.trustStore\*" -system properties. Please see the -[documentation](/reference-manual/native-image/CertificateManagement/) for more -details. - +Native-image provides multiple ways to specify the certificate file used to define the default TrustStore. +While the default behavior for native-image is to capture and use the default TrustStore from the buildtime host environment, this can be changed at runtime by setting the "javax.net.ssl.trustStore\*" system properties. +Please see the [documentation](/reference-manual/native-image/CertificateManagement/) for more details. In addition, developers can run the native image builder in a dedicated environment, such as a container, that does not contain any sensitive information in the first place. diff --git a/docs/tools/chrome-debugger.md b/docs/tools/chrome-debugger.md index 5d87871181d2..d97fef5bdb77 100644 --- a/docs/tools/chrome-debugger.md +++ b/docs/tools/chrome-debugger.md @@ -8,9 +8,11 @@ redirect_from: /docs/tools/chrome-debugger/ # Chrome Debugger -GraalVM supports debugging of guest language applications and provides a built-in implementation of the [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/). This allows you to attach compatible debuggers such as [Chrome Developer Tools](https://developers.google.com/web/tools/chrome-devtools/) to GraalVM. +GraalVM supports debugging of guest language applications and provides a built-in implementation of the [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/). +This allows you to attach compatible debuggers such as [Chrome Developer Tools](https://developers.google.com/web/tools/chrome-devtools/) to GraalVM. To debug guest language applications, pass the `--inspect` option to the command line launcher, as in the following example with a Node.js _HelloWorld_ program: + ```javascript var http = require('http'); @@ -26,11 +28,10 @@ console.log("Server running at http://localhost:8000/"); 1. Save this program as `HelloWorld.js` and then run: ```shell -node --inspect --jvm HelloWorld.js -Debugger listening on port 9229. -To start debugging, open the following URL in Chrome: - devtools://devtools/bundled/js_app.html?ws=127.0.1.1:9229/76fcb6dd-35267eb09c3 -Server running at http://localhost:8000/ +$JAVA_HOME/bin/node --inspect --jvm HelloWorld.js +Debugger listening on ws://127.0.0.1:9229/SBqxI5YIqtREaDrXkFr8hLE0HL1AfKx8TjkI8qPMq2s +For help, see: https://www.graalvm.org/tools/chrome-debugger +E.g. in Chrome open: devtools://devtools/bundled/js_app.html?ws=127.0.0.1:9229/SBqxI5YIqtREaDrXkFr8hLE0HL1AfKx8TjkI8qPMq2s ``` 2. Navigate to `http://localhost:8000/` in your browser to launch the node application. diff --git a/docs/tools/code-coverage.md b/docs/tools/code-coverage.md index 5367925cbe33..bc00b2f47e19 100644 --- a/docs/tools/code-coverage.md +++ b/docs/tools/code-coverage.md @@ -7,22 +7,14 @@ permalink: /tools/code-coverage/ # Code Coverage Command Line Tool -As of version 19.3.0, GraalVM provides a **code coverage command line tool** -that lets users record and analyze the source code coverage of a particular execution -of code. +GraalVM provides a **code coverage command line tool** that lets users record and analyze the source code coverage of a particular execution of code. -Code coverage, as a percentage of source code lines, functions, or statements -covered, is an important metric for understanding a particular source code -execution, and is commonly associated with test quality (test coverage). -Providing a visual coverage overview for individual lines of code shows the -developer which code paths are covered and which are not, giving insight into -the character of the execution which can, for example, inform further testing -efforts. +Code coverage, as a percentage of source code lines, functions, or statements covered, is an important metric for understanding a particular source code execution, and is commonly associated with test quality (test coverage). +Providing a visual coverage overview for individual lines of code shows the developer which code paths are covered and which are not, giving insight into the character of the execution which can, for example, inform further testing efforts. -The example application below will be used to demonstrate GraalVM's code -coverage capabilities. This application defines a -`getPrime` function that calculates the n-th prime using a basic prime number -calculator based on the [Sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes) algorithm. It also has a somewhat naive cache of the first 20 prime numbers. +The example application below will be used to demonstrate GraalVM's code coverage capabilities. +This application defines a `getPrime` function that calculates the n-th prime using a basic prime number calculator based on the [Sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes) algorithm. +It also has a somewhat naive cache of the first 20 prime numbers. 1. Copy the following code into a new file named `primes.js`: @@ -96,11 +88,10 @@ Shows what percent of each element was covered during execution /path/to/primes.js | 20.69% | 26.67% | 22.22% -------------------------------------------------------- ``` -The tracer prints a coverage histogram for each source file. You can see that -statement coverage is roughly 20%, line coverage is roughly 26%, and root coverage (the -term "root" covers functions, methods, etc.) is 22.22%. This tells your that our -simple tests are not particularly good at exercising the source code. Next you -will figure out which parts of the code are not covered. +The tracer prints a coverage histogram for each source file. +You can see that statement coverage is roughly 20%, line coverage is roughly 26%, and root coverage (the term "root" covers functions, methods, etc.) is 22.22%. +This tells your that our simple tests are not particularly good at exercising the source code. +Next you will figure out which parts of the code are not covered. 4. Run `js primes.js --coverage --coverage.Output=detailed`. Prepare for a somewhat verbose output. Specifying the output as `detailed` will print all the source code lines with a @@ -175,21 +166,16 @@ p if (n > cache.length) { return calculatePrime(n); } -------------------------------------------------------- ``` -As the legend at the beginning of the output explains, lines that are covered by -the execution are preceded with a `+`. Lines not covered by the execution are -preceded with a `-`. Lines that are covered partially are preceded with `p` (e.g., when an `if` -statement is covered but only one branch is taken, consider the other bench -to be incidentally covered). +As the legend at the beginning of the output explains, lines that are covered by the execution are preceded with a `+`. +Lines not covered by the execution are preceded with a `-`. +Lines that are covered partially are preceded with `p` (e.g., when an `if` statement is covered but only one branch is taken, consider the other bench to be incidentally covered). -Looking at the output you can see that the `calculatePrime` function and all its -calls are never executed. Looking again at the assertions and the `getPrime` -function, it becomes clear that our tests always hit the cache. Thus most of the -code is never executed. You can improve on that. +Looking at the output you can see that the `calculatePrime` function and all its calls are never executed. Looking again at the assertions and the `getPrime` +function, it becomes clear that our tests always hit the cache. +Thus most of the code is never executed. You can improve on that. -5. Add `console.assert(getPrime(30) == 113);` to the end of the `primes.js` file -and run `js primes.js --coverage`. Since the new assertion added calls -`getPrime` with 30 (our cache only has 20 entries) the coverage will look like -this: +5. Add `console.assert(getPrime(30) == 113);` to the end of the `primes.js` file and run `js primes.js --coverage`. Since the new assertion added calls +`getPrime` with 30 (our cache only has 20 entries) the coverage will look like this: ```shell js primes.js --coverage @@ -205,11 +191,9 @@ Code coverage histogram. ## Integrating with Other Tools -The code coverage tool provides ways to integrate with other tools. Running -with `--coverage.Output=lcov` produces output in the commonly used -[lcov](https://linux.die.net/man/1/lcov) format which is used by multiple tools -(e.g., `genhtml`) to display coverage data. Take a look at the next example that -shows how to visualise coverage of a Node.js app with Visual Studio Code. +The code coverage tool provides ways to integrate with other tools. +Running with `--coverage.Output=lcov` produces output in the commonly used [lcov](https://linux.die.net/man/1/lcov) format which is used by multiple tools (e.g., `genhtml`) to display coverage data. +Take a look at the next example that shows how to visualise coverage of a Node.js app with Visual Studio Code. 1. Copy the following code into a new file named `nodeapp.js`: @@ -232,29 +216,27 @@ app.get('/shutdown', (req, res) => { app.listen(port, () => console.log(`Example app listening on port ${port}!`)) ``` -2. Install the express module dependency: `npm install express`. +2. Install the express module dependency: +```shell +$JAVA_HOME/bin/npm install express +``` 3. Launch Visual Studio Code and install a code coverage plugin that supports _lcov_. The [Code Coverage Highlighter](https://marketplace.visualstudio.com/items?itemName=brainfit.vscode-coverage-highlighter) is used for this example, but other plugins should work similarly. 4. Run the _nodeapp.js_ file with coverage enabled and configured: ```shell -node --coverage --coverage.Output=lcov \ +$JAVA_HOME/bin/node --coverage --coverage.Output=lcov \ --coverage.OutputFile=coverage/lcov.info \ nodeapp.js ``` -Note that the Code Coverage Highlighter plugin looks for the `lcov.info` file in -the `coverage` directory by default, so direct the output of the code -coverage tool there. +Note that the Code Coverage Highlighter plugin looks for the `lcov.info` file in the `coverage` directory by default, so direct the output of the code coverage tool there. 5. Visit [localhost:3000/](http://localhost:3000/) in your browser, then visit [localhost:3000/shutdown](http://localhost:3000/shutdown) to close the app. -6. Open Visual Studio Code, then open the folder containing the `nodeapp.js` file -and `coverage` directory and you should be greeted with an image similar to the following: +6. Open Visual Studio Code, then open the folder containing the `nodeapp.js` file and `coverage` directory and you should be greeted with an image similar to the following: ![](img/vscode-coverage.png) -If you wish to integrate the data gathered by the GraalVM code coverage tool -with your own visualisation, the `--coverage.Output=json` option results in -the output being a JSON file with the raw data gathered by the tracker. +If you wish to integrate the data gathered by the GraalVM code coverage tool with your own visualisation, the `--coverage.Output=json` option results in the output being a JSON file with the raw data gathered by the tracker. diff --git a/docs/tools/dap.md b/docs/tools/dap.md index c890f7b60aea..ab44d5c97664 100644 --- a/docs/tools/dap.md +++ b/docs/tools/dap.md @@ -7,7 +7,7 @@ permalink: /tools/dap/ # Debug Adapter Protocol -GraalVM supports debugging of guest language applications, written in any of the supported languages, i.e., JavaScript/TypeScript, Python R, Ruby, and provides a built-in implementation of the [Debug Adapter Protocol (DAP)](https://microsoft.github.io/debug-adapter-protocol/). +GraalVM supports debugging of guest language applications, written in any of the supported languages, i.e., JavaScript/TypeScript, Python, R, Ruby, and provides a built-in implementation of the [Debug Adapter Protocol (DAP)](https://microsoft.github.io/debug-adapter-protocol/). By definition, Debug Adapter Protocol is to standardize the "communication" between the debugging component and a concrete debugger or runtime. This allows you to attach compatible debuggers such as Visual Studio Code (VS Code) to GraalVM. @@ -41,12 +41,12 @@ app.listen(port, () => console.log(`Example app listening on port ${port}!`)) 2. Install the `express` module dependency in the directory where you saved the file: ```shell -npm install express +$JAVA_HOME/bin/npm install express ``` 3. Run the application with DAP enabled: ```shell -node --dap App.js +$JAVA_HOME/bin/node --dap App.js [Graal DAP] Starting server and listening on localhost/127.0.0.1:4711 ``` @@ -77,10 +77,10 @@ code . 8. Start debugging (F5). The other approach is to use VS Code with the GraalVM extension installed. -Follow the steps described in -[Node.js and JavaScript Debugging](https://marketplace.visualstudio.com/items?itemName=oracle-labs-graalvm.graalvm#javascript-and-node.js-debugging), and launch the application being debugged directly from VS Code. +Follow the steps described in [Node.js and JavaScript Debugging](https://marketplace.visualstudio.com/items?itemName=oracle-labs-graalvm.graalvm#javascript-and-node.js-debugging), and launch the application being debugged directly from VS Code. When debugging a guest language application from VS Code, a user can choose a protocol to use by setting the protocol attribute in the corresponding debug configuration to either `chromeDevTools` or `debugAdapter`. To connect to the open DAP port in this scenario, the content of the _launch.json_ should be: + ```json { "version": "0.2.0", diff --git a/docs/tools/graalvm-insight.md b/docs/tools/graalvm-insight.md index daafa72079c7..77273ec3afc1 100644 --- a/docs/tools/graalvm-insight.md +++ b/docs/tools/graalvm-insight.md @@ -7,22 +7,20 @@ permalink: /tools/graalvm-insight/ # GraalVM Insight -GraalVM Insight is a multipurpose, flexible tool for writing reliable -microservices solutions that traces program runtime behavior and gathers insights. +* [Start Using GraalVM Insight](#start-using-graalvm-insight) +* [Polyglot Tracing](#polyglot-tracing) +* [Inspecting Values](#inspecting-values) -The dynamic nature of the tool helps users to selectively apply tracing pointcuts on -already running applications with no loss of performance. Insight -also provides detailed access to runtime behavior of a program, allowing users to -inspect values and types at invocation or allocation sites. GraalVM Insight further permits users to -modify computed values, interrupt execution, and quickly experiment with -behavioral changes without modifying the application code. +GraalVM Insight is a multipurpose, flexible tool for writing reliable microservices solutions that traces program runtime behavior and gathers insights. + +The dynamic nature of the tool helps users to selectively apply tracing pointcuts on already running applications with no loss of performance. +GraalVM Insight also provides detailed access to runtime behavior of a program, allowing users to inspect values and types at invocation or allocation sites. +The tool further permits users to modify computed values, interrupt execution, and quickly experiment with behavioral changes without modifying the application code. This page provides information on GraalVM Insight as of the 20.1 version. To learn about Insight on versions 20.0 and 19.3, proceed [here](https://github.com/oracle/graal/blob/release/graal-vm/20.0/tools/docs/T-Trace.md). -Note: The GraalVM Insight tool is offered as a technology preview and requires the user to -pass the `--experimental-options` option in order to enable the `--insight` -instrument. +Note: The GraalVM Insight tool is offered as a technology preview and requires the user to pass the `--experimental-options` option in order to enable the `--insight` instrument. ## Start Using GraalVM Insight @@ -32,30 +30,25 @@ insight.on('source', function(ev) { print(`Loading ${ev.characters.length} characters from ${ev.name}`); }); ``` -2. Having set `JAVA_HOME` to the GraalVM home directory, start the `node` launcher with -the `--insight` tool and observe what scripts are being loaded and -evaluated: +2. Having set `JAVA_HOME` to the GraalVM home directory, start the `node` launcher with the `--insight` tool and observe what scripts are being loaded and evaluated: ```shell $JAVA_HOME/bin/node --experimental-options --insight=source-tracing.js --js.print -e "print('The result: ' + 6 * 7)" | tail -n 10 -Loading 29938 characters from url.js -Loading 345 characters from internal/idna.js -Loading 12642 characters from punycode.js -Loading 33678 characters from internal/modules/cjs/loader.js -Loading 13058 characters from vm.js -Loading 52408 characters from fs.js -Loading 15920 characters from internal/fs/utils.js -Loading 505 characters from [eval]-wrapper +Loading 215 characters from internal/modules/esm/transform_source.js +Loading 12107 characters from internal/modules/esm/translators.js +Loading 1756 characters from internal/modules/esm/create_dynamic_module.js +Loading 12930 characters from internal/vm/module.js +Loading 2710 characters from internal/modules/run_main.js +Loading 308 characters from module.js +Loading 10844 characters from internal/source_map/source_map.js +Loading 170 characters from [eval]-wrapper Loading 29 characters from [eval] The result: 42 ``` -The _source-tracing.js_ script used the provided `insight` object to -attach a source listener to the runtime. Whenever the script was loaded, the -listener got notified of it and could take an action -- printing the length and -name of the processed script. +The _source-tracing.js_ script used the provided `insight` object to attach a source listener to the runtime. +Whenever the script was loaded, the listener got notified of it and could take an action -- printing the length and name of the processed script. The Insight information can be collected to a print statement or a histogram. -The following _function-histogram-tracing.js_ script counts all method invocations -and dumps the most frequent ones when the execution of a program is over: +The following _function-histogram-tracing.js_ script counts all method invocations and dumps the most frequent ones when the execution of a program is over: ```javascript var map = new Map(); @@ -90,39 +83,31 @@ insight.on('enter', function(ev) { insight.on('close', dumpHistogram); ``` -The `map` is a global variable shared inside of the Insight script that allows the -code to share data between the `insight.on('enter')` function and the `dumpHistogram` -function. The latter is executed when the node process execution is over -(registered via `insight.on('close', dumpHistogram`). Invoke it as: +The `map` is a global variable shared inside of the Insight script that allows the code to share data between the `insight.on('enter')` function and the `dumpHistogram` +function. +The latter is executed when the node process execution is over (registered via `insight.on('close', dumpHistogram`). +Invoke it as: ```shell $JAVA_HOME/bin/node --experimental-options --insight=function-histogram-tracing.js --js.print -e "print('The result: ' + 6 * 7)" The result: 42 -=== Histogram === -543 calls to isPosixPathSeparator -211 calls to E -211 calls to makeNodeErrorWithCode -205 calls to NativeModule -198 calls to uncurryThis -154 calls to :=> -147 calls to nativeModuleRequire -145 calls to NativeModule.compile - 55 calls to internalBinding - 53 calls to :anonymous - 49 calls to :program - 37 calls to getOptionValue - 24 calls to copyProps +==== Histogram ==== +328 calls to isPosixPathSeparator +236 calls to E +235 calls to makeNodeErrorWithCode +137 calls to :=> + 64 calls to :program + 64 calls to :anonymous + 45 calls to getOptionValue + 45 calls to getOptionsFromBinding + 26 calls to hideStackFrames 18 calls to validateString - 13 calls to copyPrototype - 13 calls to hideStackFrames - 13 calls to addReadOnlyProcessAlias -================= + 12 calls to defineColorAlias +=================== ``` ## Polyglot Tracing -The previous examples were written in JavaScript, but due to GraalVM's polyglot -nature, you can take the same instrument and use it in a program written in, -e.g., the Ruby language. +The previous examples were written in JavaScript, but due to GraalVM's polyglot nature, you can take the same instrument and use it in a program written in, e.g., the Ruby language. 1. Create the _source-trace.js_ file: ```javascript @@ -145,8 +130,7 @@ Hello from GraalVM Ruby! ``` It is necessary to start the Ruby launcher with the `--polyglot` parameter, as the _source-tracing.js_ script remains written in JavaScript. -A user can instrument any language on top of GraalVM, but also the Insight scripts can be -written in any of the GraalVM supported languages (implemented with the [Truffle language implementation framework](../graalvm-as-a-platform/truffle-framework/README.md)). +A user can instrument any language on top of GraalVM, but also the Insight scripts can be written in any of the GraalVM supported languages (implemented with the [Truffle language implementation framework](../../truffle/docs/README.md)). 1. Create the _source-tracing.rb_ Ruby file: ```ruby @@ -178,10 +162,9 @@ With Ruby: 42 ## Inspecting Values -GraalVM Insight not only allows one to trace where the program execution is happening, -it also offers access to values of local variables and function arguments during -program execution. You can, for example, write an instrument that shows the value of -argument `n` in the function `fib`: +GraalVM Insight not only allows one to trace where the program execution is happening, it also offers access to values of local variables and function arguments during program execution. +You can, for example, write an instrument that shows the value of argument `n` in the function `fib`: + ```javascript insight.on('enter', function(ctx, frame) { print('fib for ' + frame.n); @@ -191,9 +174,9 @@ insight.on('enter', function(ctx, frame) { }); ``` -This instrument uses the second function argument, `frame`, to get access to values of -local variables inside every instrumented function. The above script -also uses `rootNameFilter` to apply its hook only to the function named `fib`: +This instrument uses the second function argument, `frame`, to get access to values of local variables inside every instrumented function. +The above script also uses `rootNameFilter` to apply its hook only to the function named `fib`: + ```javascript function fib(n) { if (n < 1) return 0; @@ -203,9 +186,7 @@ function fib(n) { print("Two is the result " + fib(3)); ``` -When the instrument is stored in a `fib-trace.js` file and the actual code is in -`fib.js`, invoking the following command yields detailed information about the -program execution and parameters passed between function invocations: +When the instrument is stored in a `fib-trace.js` file and the actual code is in `fib.js`, invoking the following command yields detailed information about the program execution and parameters passed between function invocations: ```shell $JAVA_HOME/bin/node --experimental-options --insight=fib-trace.js --js.print fib.js fib for 3 diff --git a/docs/tools/ideal-graph-visualizer.md b/docs/tools/ideal-graph-visualizer.md index 8c2ab3321b41..3fd2e430f3fa 100644 --- a/docs/tools/ideal-graph-visualizer.md +++ b/docs/tools/ideal-graph-visualizer.md @@ -7,13 +7,17 @@ permalink: /tools/igv/ # Ideal Graph Visualizer -Ideal Graph Visualizer (IGV) is a developer tool allowing users to analyze compilation -graphs and investigate performance issues. The tool is essential for any -language implementers building on top of **Oracle GraalVM Enterprise Edition**. It is -available as a separate download on [Oracle Technology Network](https://www.oracle.com/technetwork/oracle-labs/program-languages/downloads/index.html) and requires accepting the Oracle Technology Network Developer License. +* [Browsing Graphs](#browsing-graphs) +* [Viewing Source Code](#viewing-source-code) +* [Dumping Graphs](#dumping-graphs) + +Ideal Graph Visualizer (IGV) is a developer tool allowing users to analyze compilation graphs and investigate performance issues. +The tool is essential for any language implementers building on top of **Oracle GraalVM Enterprise Edition**. +It is available as a separate download on [Oracle Technology Network](https://www.oracle.com/downloads/graalvm-downloads.html) and requires accepting the Oracle Technology Network Developer License. IGV is developed to view and inspect intermediate representation graphs -- a language-independent intermediate representation (IR) between the source -language and the machine code, generated by the compiler. See [Dumping Graphs](/tools/igv/#dumping-graphs) below. +language and the machine code, generated by the compiler. +See [Dumping Graphs](#dumping-graphs) below. 1. Unzip the downloaded package and enter `bin` directory: ```shell @@ -40,13 +44,13 @@ puts js_obj[:msg] puts js_obj[:payload].join(' ') ``` -4. From another console window, make sure the `ruby` runtime is available in GraalVM Enterprise, -and connect the `Test.rb` script to the running IGV: +4. From another console window, make sure the `ruby` runtime is available in GraalVM Enterprise, and connect the `Test.rb` script to the running IGV: ```shell gu list ruby --jvm --polyglot --vm.Dgraal.Dump=:1 --vm.Dgraal.PrintGraph=Network Test.rb ``` -This causes GraalVM Enterprise to dump compiler graphs in the IGV format over the network to an IGV process listening on `127.0.0.1:4445`. Once the connection is made, you are able to see the graphs in the Outline window. +This causes GraalVM Enterprise to dump compiler graphs in the IGV format over the network to an IGV process listening on `127.0.0.1:4445`. +Once the connection is made, you are able to see the graphs in the Outline window. Find, e.g., the `java.lang.String.char(int)` folder and open its After Parsing graph by double-clicking. If the node has `sourceNodePosition` property, then the Processing window will attempt to display its location and the entire stacktrace. @@ -58,57 +62,48 @@ Select a node in the graph and press the Go to Source button in the Stack View w ![](img/IGV_add_source.png) -Graphs navigation is also available from the Context menu, enabled by focusing -and right-clicking a specific graph node. The Extract Nodes option will re-render -a graph and display only the selected nodes and their neighbors. +Graphs navigation is also available from the Context menu, enabled by focusing and right-clicking a specific graph node. +The Extract Nodes option will re-render a graph and display only the selected nodes and their neighbors. ![](img/IGV_context_menu.png) -If the graph is larger than the screen, manipulate with the Satellite view button -in the main toolbar to move the viewport rectangle. +If the graph is larger than the screen, manipulate with the Satellite view button in the main toolbar to move the viewport rectangle. ![](img/IGV_satellite_view.png) -For user preference, the graph color scheme is adjustable by editing -the Coloring filter, enabled by default in the left sidebar. +For user preference, the graph color scheme is adjustable by editing the Coloring filter, enabled by default in the left sidebar. ## Viewing Source Code -Source code views can be opened in manual and assisted modes. Once you select a node -in the graph view, the Processing view will open. If the IGV knows where the source code -for the current frame is, the green Go to Source arrow is enabled. If the IGV does not -know where the source is, the line is greyed out and a Looking Glass button appears. +Source code views can be opened in manual and assisted modes. +Once you select a node in the graph view, the Processing view will open. +If the IGV knows where the source code for the current frame is, the green Go to Source arrow is enabled. +If the IGV does not know where the source is, the line is greyed out and a Looking Glass button appears. ![](img/IGV_add_source.png) Press it and select Locate in Java project to locate the correct project in the dialog. The IGV hides projects which do not contain the required source file. The Source Collections serves to display the stand alone roots added by "Add root of sources" general action. -If the source is located using the preferred method (i.e., from a Java project), -its project can be later managed on the Project tab. That one is initially hidden, -but you can display the list of opened projects using Window -> Projects. +If the source is located using the preferred method (i.e., from a Java project), its project can be later managed on the Project tab. +That one is initially hidden, but you can display the list of opened projects using Window -> Projects. ## Dumping Graphs -The IGV tool is developed to allow GraalVM Enterprise language implementers -to optimize their languages assembled with the [Language Implentation Framework](/graalvm-as-a-platform/language-implementation-framework/). As a development -tool it should not be installed to production environments. - -To dump the GraalVM compiler graphs from an embedded Java application to the IGV, -you need to add options to GraalVM-based processes. Depending on the language/VM -used, you may need to prefix the options by `--vm`. See the particular -language's documentation for the details. The main option to add is -`-Dgraal.Dump=:1`. This will dump graphs in an IGV readable format to the local -file system. To send the dumps directly to the IGV over the network, add -`-Dgraal.PrintGraph=Network` when starting a GraalVM instance. Optionally a -port can be specified. Then dumps are sent to the IGV from the running GraalVM on -localhost. If the IGV does not listen on localhost, Options -> Ideal Graph Settings| -Accept Data From Network can be checked. If there is not an IGV instance -listening on `127.0.0.1` or it cannot be connected to, the dumps will be -redirected to the local file system. The file system location is `graal_dumps/` -under the current working directory of the process and can be changed with the -`-Dgraal.DumpPath` option. - -In case an older GraalVM Enterprise is used, you may need to explicitly request that dumps -include the `nodeSourcePosition` property. This is done by adding the -`-XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints` options. +The IGV tool is developed to allow GraalVM Enterprise language implementers to optimize their languages assembled with the [Language Implentation Framework](../../truffle/docs/README.md). +As a development tool it should not be installed to production environments. + +To dump the GraalVM compiler graphs from an embedded Java application to the IGV, you need to add options to GraalVM-based processes. +Depending on the language/VM used, you may need to prefix the options by `--vm`. +See the particular language's documentation for the details. +The main option to add is `-Dgraal.Dump=:1`. +This will dump graphs in an IGV readable format to the local file system. +To send the dumps directly to the IGV over the network, add `-Dgraal.PrintGraph=Network` when starting a GraalVM instance. +Optionally a port can be specified. +Then dumps are sent to the IGV from the running GraalVM on localhost. +If the IGV does not listen on localhost, Options -> Ideal Graph Settings|Accept Data From Network can be checked. +If there is not an IGV instance listening on `127.0.0.1` or it cannot be connected to, the dumps will be redirected to the local file system. +The file system location is `graal_dumps/` under the current working directory of the process and can be changed with the `-Dgraal.DumpPath` option. + +In case an older GraalVM Enterprise is used, you may need to explicitly request that dumps include the `nodeSourcePosition` property. +This is done by adding the `-XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints` options. diff --git a/docs/tools/img/profiler_flamegraph.png b/docs/tools/img/profiler_flamegraph.png index 86a0deb01d5c..4d849d45ff44 100644 Binary files a/docs/tools/img/profiler_flamegraph.png and b/docs/tools/img/profiler_flamegraph.png differ diff --git a/docs/tools/lsp.md b/docs/tools/lsp.md index f831f89238ad..b005ca443c3b 100644 --- a/docs/tools/lsp.md +++ b/docs/tools/lsp.md @@ -7,23 +7,23 @@ permalink: /tools/lsp/ # Language Server Protocol -GraalVM supports [Language Server Protocol](https://microsoft.github.io/language-server-protocol/) (LSP) for guest languages. It provides features like code-completion, find usages and alike for the client tools -- IDEs like Visual Studio Code. +GraalVM supports [Language Server Protocol](https://microsoft.github.io/language-server-protocol/) (LSP) for guest languages. +It provides features like code-completion, find usages and alike for the client tools -- IDEs like Visual Studio Code. -To start the GraalVM Language Server, pass the `--lsp` option to the command -line launcher as in the following example with a Node.js application. +To start the GraalVM Language Server, pass the `--lsp` option to the command line launcher as in the following example with a Node.js application. -Note: The GraalVM Language Server is offered as a technology preview and requires the -user to pass the `--experimental-options` option for its activation. +Note: The GraalVM Language Server is offered as a technology preview and requires the user to pass the `--experimental-options` option for its activation. ```shell -node --experimental-options --lsp app.js +$JAVA_HOME/bin/node --experimental-options --lsp app.js [Graal LSP] Starting server and listening on localhost/127.0.0.1:8123 Example app listening on port 3000! ``` ![](img/vscode_cc_1.png) _GraalVM Enterprise-provided code completion for R script, part of the Node.js Polyglot application_ -The GraalVM Language Server itself does not provide the static data usually gathered by parsing the application sources (as these data are sometimes fuzzy in the cases of dynamic languages). Instead, the Language Server was designed to provide the accurate dynamic data gathered from the application runtime. +The GraalVM Language Server itself does not provide the static data usually gathered by parsing the application sources (as these data are sometimes fuzzy in the cases of dynamic languages). +Instead, the Language Server was designed to provide the accurate dynamic data gathered from the application runtime. However, the Language Server could delegate to the existing language servers written specially for the particular languages (using the `--lsp.Delegates` launcher option) and merge the static data returned from these servers with its own dynamic data to a single result. diff --git a/docs/tools/profiling.md b/docs/tools/profiling.md index f5cc19a9e5f3..1b07d5bd0528 100644 --- a/docs/tools/profiling.md +++ b/docs/tools/profiling.md @@ -7,17 +7,13 @@ permalink: /tools/profiling/ # Profiling Command Line Tools -GraalVM **profiling command line tools** help you optimize your code -through analysis of CPU and memory usage. +GraalVM **profiling command line tools** help you optimize your code through analysis of CPU and memory usage. -Most applications spend 80% of their runtime in 20% of the code. For this -reason, to optimize the code, it is essential to know where the application -spends its time. In this section, we use an example application to demonstrate -the three main profiling capabilities that GraalVM offers: CPU Tracer, CPU -Sampler, and Memory Tracer. +Most applications spend 80% of their runtime in 20% of the code. +For this reason, to optimize the code, it is essential to know where the application spends its time. +In this section, we use an example application to demonstrate the three main profiling capabilities that GraalVM offers: CPU Tracer, CPU Sampler, and Memory Tracer. -This example application uses a basic prime -number calculator based on the [Sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes) +This example application uses a basic prime number calculator based on the [Sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes) algorithm. 1. Copy the following code into a new file named `primes.js`: @@ -84,36 +80,34 @@ algorithm. js primes.js --cpusampler Computed 5000 prime numbers. The last 5 are 48563,48571,48589,48593,48611. - ---------------------------------------------------------------------------------------------------- - Sampling Histogram. Recorded 825 samples with period 10ms. + ---------------------------------------------------------------------------------------------- + Sampling Histogram. Recorded 250 samples with period 10ms. Self Time: Time spent on the top of the stack. Total Time: Time spent somewhere on the stack. - ---------------------------------------------------------------------------------------------------- + ---------------------------------------------------------------------------------------------- Thread[main,5,main] - Name | Total Time || Self Time || Location - ---------------------------------------------------------------------------------------------------- - accept | 7330ms 88.8% || 7330ms 88.8% || primes.js~13-22:191-419 - :program | 8250ms 100.0% || 420ms 5.1% || primes.js~1-46:0-982 - next | 7820ms 94.8% || 250ms 3.0% || primes.js~31-37:537-737 - DivisibleByFilter | 440ms 5.3% || 240ms 2.9% || primes.js~7-23:66-421 - AcceptFilter | 20ms 0.2% || 10ms 0.1% || primes.js~1-5:0-63 - Primes | 20ms 0.2% || 0ms 0.0% || primes.js~25-38:424-739 - ---------------------------------------------------------------------------------------------------- + Name || Total Time || Self Time || Location + ---------------------------------------------------------------------------------------------- + accept || 2150ms 86.0% || 2150ms 86.0% || primes.js~13-22:191-419 + next || 2470ms 98.8% || 320ms 12.8% || primes.js~31-37:537-737 + :program || 2500ms 100.0% || 30ms 1.2% || primes.js~1-46:0-982 + ---------------------------------------------------------------------------------------------- ``` + By default the sampler prints an execution time histogram for each JavaScript function. - You can produce a flame graph in SVG format by doing + + You can produce a flame graph in SVG format by requesting that with the `--cpusampler.Output=flamegraph` option: ```shell js primes.js --cpusampler --cpusampler.Output=flamegraph --cpusampler.OutputFile=primes.svg ``` - which should produce something like this - + It should produce something like this: + ![](img/profiler_flamegraph.png) - + You can zoom into the graph by clicking on elements. - By default, CPU sampling takes a sample every 10 milliseconds. From the - result, we can see that roughly 89% of the time is spent - in the `DivisibleByFilter.accept` function. + By default, CPU sampling takes a sample every 10 milliseconds. + From the result, we can see that roughly 89% of the time is spent in the `DivisibleByFilter.accept` function. ```javascript accept(n) { @@ -129,71 +123,59 @@ algorithm. ``` Now use the CPU Tracer to collect execution counts of each statement: -4. Run `js primes.js --cputracer --cputracer.TraceStatements --cputracer.FilterRootName=*accept` -to collect execution counts for all statements in methods ending with `accept`: +4. Run `js primes.js --cputracer --cputracer.TraceStatements --cputracer.FilterRootName=*accept` to collect execution counts for all statements in methods ending with `accept`: ```shell - js primes.js --cputracer --cputracer.TraceStatements --cputracer.FilterRootName=*accept + js primes.js --cputracer --cputracer.TraceStatements --cputracer.FilterRootName=accept Computed 5000 prime numbers. The last 5 are 48563,48571,48589,48593,48611. ----------------------------------------------------------------------------------------- - Tracing Histogram. Counted a total of 351278226 element executions. + Tracing Histogram. Counted a total of 468336895 element executions. Total Count: Number of times the element was executed and percentage of total executions. Interpreted Count: Number of times the element was interpreted and percentage of total executions of this element. Compiled Count: Number of times the compiled element was executed and percentage of total executions of this element. ----------------------------------------------------------------------------------------- Name | Total Count | Interpreted Count | Compiled Count | Location ----------------------------------------------------------------------------------------- - accept | 117058669 33.3% | 63575 0.1% | 116995094 99.9% | primes.js~15:245-258 - accept | 117053670 33.3% | 63422 0.1% | 116990248 99.9% | primes.js~16-18:275-348 - accept | 117005061 33.3% | 61718 0.1% | 116943343 99.9% | primes.js~19:362-381 - accept | 53608 0.0% | 1857 3.5% | 51751 96.5% | primes.js~14:215-227 - accept | 53608 0.0% | 1857 3.5% | 51751 96.5% | primes.js~13-22:191-419 - accept | 48609 0.0% | 1704 3.5% | 46905 96.5% | primes.js~17:322-334 - accept | 4999 0.0% | 153 3.1% | 4846 96.9% | primes.js~21:409-412 + accept | 234117338 50.0% | 365660 0.2% | 233751678 99.8% | primes.js~15:245-258 + accept | 117053670 25.0% | 182582 0.2% | 116871088 99.8% | primes.js~16-18:275-348 + accept | 117005061 25.0% | 181001 0.2% | 116824060 99.8% | primes.js~19:362-381 + accept | 53608 0.0% | 1829 3.4% | 51779 96.6% | primes.js~14:211-227 + accept | 53608 0.0% | 1829 3.4% | 51779 96.6% | primes.js~13-22:191-419 + accept | 48609 0.0% | 1581 3.3% | 47028 96.7% | primes.js~17:322-334 + accept | 4999 0.0% | 248 5.0% | 4751 95.0% | primes.js~21:402-413 accept | 1 0.0% | 1 100.0% | 0 0.0% | primes.js~2-4:25-61 - accept | 1 0.0% | 1 100.0% | 0 0.0% | primes.js~3:52-55 + accept | 1 0.0% | 1 100.0% | 0 0.0% | primes.js~3:45-55 ----------------------------------------------------------------------------------------- ``` - The output shows execution counters for each statement, instead of timing - information. Tracing histograms often provides insights into the behavior - of the algorithm that needs optimization. + The output shows execution counters for each statement, instead of timing information. + Tracing histograms often provides insights into the behavior of the algorithm that needs optimization. -5. Run `js primes.js --experimental-options --memtracer` to display source code locations and -counts of reported allocations. Note that the Memory Tracer tool for capturing allocations is currently an -experimental feature in GraalVM. As such, `--memtracer` must -be preceded by the `--experimental-options` command line option. +5. Run `js primes.js --experimental-options --memtracer` to display source code locations and counts of reported allocations. Note that the Memory Tracer tool for capturing allocations is currently an experimental feature in GraalVM. As such, `--memtracer` must be preceded by the `--experimental-options` command line option. ```shell js primes.js --experimental-options --memtracer Computed 5000 prime numbers. The last 5 are 48563,48571,48589,48593,48611. ------------------------------------------------------------ - Location Histogram with Allocation Counts. Recorded a total of 5013 allocations. - Total Count: Number of allocations during the execution of this element. - Self Count: Number of allocations in this element alone (excluding sub calls). - ------------------------------------------------------------ - Name | Self Count | Total Count | Location - ------------------------------------------------------------ - next | 5000 99.7% | 5000 99.7% | primes.js~31-37:537-737 - :program | 11 0.2% | 5013 100.0% | primes.js~1-46:0-966 - Primes | 1 0.0% | 1 0.0% | primes.js~25-38:454-739 - ------------------------------------------------------------ - + Location Histogram with Allocation Counts. Recorded a total of 5007 allocations. + Total Count: Number of allocations during the execution of this element. + Self Count: Number of allocations in this element alone (excluding sub calls). + -------------------------------------------------------- + Name | Self Count | Total Count | Location + -------------------------------------------------------- + next | 5000 99.9% | 5000 99.9% | primes.js~31-37:537-737 + :program | 6 0.1% | 5007 100.0% | primes.js~1-46:0-982 + Primes | 1 0.0% | 1 0.0% | primes.js~25-38:424-739 + -------------------------------------------------------- ``` - This output shows the number of allocations which were recorded per function. - For each prime number that was computed, the program allocates one object in - `next` and one in `constructor` of `DivisibleByFilter`. Allocations are recorded - independently of whether they could get eliminated by the compiler. + This output shows the number of allocations which were recorded per function. For each prime number that was computed, the program allocates one object in `next` and one in `constructor` of `DivisibleByFilter`. + Allocations are recorded independently of whether they could get eliminated by the compiler. - The GraalVM compiler is particularly powerful in optimizing allocations and can push - allocations into infrequent branches to increase execution performance. The - GraalVM team plans to add information about memory optimizations to the - memory tracer in the future. + The GraalVM compiler is particularly powerful in optimizing allocations and can push allocations into infrequent branches to increase execution performance. + The GraalVM team plans to add information about memory optimizations to the memory tracer in the future. ## Tools Options -Use the `--help:tools` option in all guest language launchers to display -reference information for CPU Sampler, CPU Tracer, and Memory Tracer. - -The current set of available options is as follows: +Use the `--help:tools` option in all guest language launchers to display reference information for CPU Sampler, CPU Tracer, and Memory Tracer. +The current set of available options is as follows. ### CPU Sampler Options @@ -203,19 +185,20 @@ The current set of available options is as follows: file paths, for example, `*program*.sl`. The default is ∗. - `--cpusampler.FilterLanguage=`: profiles languages only with the matching mime-type, for example, `+`. The default is no filter. +- `--cpusampler.FilterMimeType=`: profiles languages with mime-type. There is no filter by default. - `--cpusampler.FilterRootName=`: applies a wildcard filter for program roots, for example, `Math.*`. The default is ∗. - `--cpusampler.GatherHitTimes`: saves a timestamp for each taken sample. The default is false. +- `--cpusampler.MinSamples=`: removes elements from output if they have less samples than this value (default is `0`). - `--cpusampler.Mode=`: describes the level of sampling detail. Please note that increased detail can lead to reduced accuracy. - `exclude_inlined_roots`: samples roots excluding inlined functions (enabled by default) - `roots`: samples roots including inlined functions - `statements`: samples all statements - `--cpusampler.Output=`: prints a `histogram`, `calltree`, `json`, or `flamegraph` as output. The default is `histogram`. +- `--cpusampler.OutputFile=`: saves output to the given file. Output is printed to output stream by default. - `--cpusampler.Period=`: specifies the period, in milliseconds, to sample the stack. -- `--cpusampler.SampleInternal`: captures internal elements. The default is -false. - `--cpusampler.StackLimit=`: specifies the maximum number of stack elements. - `--cpusampler.SummariseThreads `: prints sampling output as a summary of all `per thread` profiles. The default is false. @@ -227,11 +210,12 @@ elements. file paths, for example, `*program*.sl`. The default is ∗. - `--cputracer.FilterLanguage=`: profiles languages only with the matching mime-type, for example, `+`. The default is no filter. +- `--cputracer.FilterMimeType=`: profiles languages with mime-type. There is no filter by default. - `--cputracer.FilterRootName=`: applies a wildcard filter for program roots, for example, `Math.*`. The default is ∗. - `--cputracer.Output=` prints a `histogram` or `json` as output. The default is `histogram`. +- `--cpusampler.OutputFile=`: saves output to the given file. Output is printed to output stream by default. - `--cputracer.TraceCalls`: captures calls when tracing. The default is false. -- `--cputracer.TraceInternal`: traces internal elements. The default is false. - `--cputracer.TraceRoots=`: captures roots when tracing. The default is true. - `--cputracer.TraceStatements`: captures statements when tracing. The default @@ -244,10 +228,10 @@ The memory tracer tool is currently an experimental tool. Make sure to prepend t - `--memtracer`: enables the memory tracer. Disabled by default. - `--memtracer.FilterFile=`: applies a wildcard filter for source file paths, for example, `*program*.sl`. The default is ∗. - `--memtracer.FilterLanguage=`: profiles languages only with the matching mime-type, for example, `+`. The default is no filter. +- `--memtracer.FilterMimeType=`: profiles languages with mime-type. There is no filter by default. - `--memtracer.FilterRootName=`: applies a wildcard filter for program roots, for example, `Math.*`. The default is ∗. - `--memtracer.Output=`: prints a `typehistogram`, `histogram`, or `calltree` as output. The default is `histogram`. - `--memtracer.StackLimit=`: sets the maximum number of maximum stack elements. - `--memtracer.TraceCalls`: captures calls when tracing. The default is false. -- `--memtracer.TraceInternal`: captures internal elements. The default is false. - `--memtracer.TraceRoots=`: captures roots when tracing. The default is true. - `--memtracer.TraceStatements`: captures statements when tracing. The default is false. diff --git a/docs/tools/visualvm.md b/docs/tools/visualvm.md index fd9a18b21e7c..cb34b024619e 100644 --- a/docs/tools/visualvm.md +++ b/docs/tools/visualvm.md @@ -21,66 +21,59 @@ currently available: To start VisualVM, execute `jvisualvm`. Immediately after startup, the tool shows all locally running Java processes in the Applications area, including the VisualVM process, itself. ### Capture a Heap Dump -To capture a heap dump of, for example, a Ruby application for later analysis, -start your application and let it run for a few seconds to warm up. Then -right-click its process in VisualVM and invoke the Heap Dump action. A -new heap viewer for the Ruby process opens. - -__Note:__ [Native Image](../reference-manual/native-image/README.md) does not implement the JVMTI agent, so triggering heap dump creation from the Applications area is impossible. Apply the `-H:+AllowVMInspection` flag with the `native-image` tool for native image processes. This way your application will handle signals and capture a heap dump when it receives the SIGUSR1 signal. The guest language REPL process must be started also with the `--jvm` flag to monitor it using VisualVM. This functionality is available with [GraalVM Enterprise Edition](https://www.oracle.com/downloads/graalvm-downloads.html). It is not available in GraalVM Community Edition. See the [Generating Native Heap Dumps](../reference-manual/native-image/NativeImageHeapdumpEnterprise.md) page for details on capturing heap dumps from a native image process. +To capture a heap dump of, for example, a Ruby application for later analysis, start your application and let it run for a few seconds to warm up. +Then right-click its process in VisualVM and invoke the Heap Dump action. +A new heap viewer for the Ruby process opens. + +__Note:__ [Native Image](../reference-manual/native-image/README.md) does not implement the JVMTI agent, so triggering heap dump creation from the Applications area is impossible. +Apply the `-H:+AllowVMInspection` flag with the `native-image` tool for native image processes. +This way your application will handle signals and capture a heap dump when it receives the SIGUSR1 signal. +The guest language REPL process must be started also with the `--jvm` flag to monitor it using VisualVM. +This functionality is available with [GraalVM Enterprise Edition](https://www.oracle.com/downloads/graalvm-downloads.html). +It is not available in GraalVM Community Edition. +See the [Generating Native Heap Dumps](../reference-manual/native-image/NativeImageHeapdumpEnterprise.md) page for details on capturing heap dumps from a native image process. ### Analyzing Objects -Initially the Summary view for the Java heap is displayed. To analyze the Ruby -heap, click the leftmost (Summary) dropdown in the Heap Viewer toolbar, choose -the Ruby Heap scope and select the Objects view. Now the heap viewer displays -all Ruby heap objects, aggregated by their type. +Initially the Summary view for the Java heap is displayed. +To analyze the Ruby heap, click the leftmost (Summary) dropdown in the Heap Viewer toolbar, choose the Ruby Heap scope and select the Objects view. +Now the heap viewer displays all Ruby heap objects, aggregated by their type. Expand the Proc node in the Results view to see a list of objects of this type. -Each object displays its logical value as provided by the underlying -implementation. Expand the objects to access their variables and references, -where available. +Each object displays its logical value as provided by the underlying implementation. +Expand the objects to access their variables and references, where available. ![](img/HeapViewer_objects.png) -Now enable the Preview, Variables, and References details by clicking the buttons -in the toolbar, and select the individual _ProcType_ objects. Where available, the -Preview view shows the corresponding source fragment, the Variables view shows -variables of the object, and the References view shows objects referring to the -selected object. +Now enable the Preview, Variables, and References details by clicking the buttons in the toolbar, and select the individual _ProcType_ objects. +Where available, the Preview view shows the corresponding source fragment, the Variables view shows variables of the object, and the References view shows objects referring to the selected object. -Last, use the Presets dropdown in the Heap Viewer toolbar to switch the view -from All Objects to Dominators or GC Roots. To display the heap dominators, -retained sizes must be computed first, which can take a few minutes for the -_server.rb_ example. Select the Objects aggregation in the toolbar to view the -individual dominators or GC roots. +Last, use the Presets dropdown in the Heap Viewer toolbar to switch the view from All Objects to Dominators or GC Roots. +To display the heap dominators, retained sizes must be computed first, which can take a few minutes for the _server.rb_ example. +Select the Objects aggregation in the toolbar to view the individual dominators or GC roots. ![](img/HeapViewer_objects_dominators.png) ### Analyzing Threads -Click the leftmost dropdown in the Heap Viewer toolbar and select the Threads -view for the Ruby heap. The heap viewer now displays the Ruby thread stack -trace, including local objects. The stack trace can alternatively be displayed -textually by clicking the HTML toolbar button. +Click the leftmost dropdown in the Heap Viewer toolbar and select the Threads view for the Ruby heap. +The heap viewer now displays the Ruby thread stack trace, including local objects. The stack trace can alternatively be displayed textually by clicking the HTML toolbar button. ![](img/HeapViewer_thread.png) ### Reading JFR Snapshots -The VisualVM tool bundled with GraalVM 19.2.x and later has the ability to read JFR snapshots -- snapshots taken with JDK Flight Recorder (previously Java Flight Recorder). JFR is a tool for collecting -diagnostic and profiling data about a running Java application. It is integrated -into the Java Virtual Machine (JVM) and causes almost no performance overhead, -so it can be used even in heavily loaded production environments. +The VisualVM tool bundled with GraalVM 19.2.x and later has the ability to read JFR snapshots -- snapshots taken with JDK Flight Recorder (previously Java Flight Recorder). +JFR is a tool for collecting diagnostic and profiling data about a running Java application. +It is integrated into the Java Virtual Machine (JVM) and causes almost no performance overhead, so it can be used even in heavily loaded production environments. To install the JFR support, released as a plugin: 1. Run `/bin/jvisualvm` to start VisualVM; 2. Navigate to Tools > Plugins > Available Plugins to list all available plugins, then install the _VisualVM-JFR_ and _VisualVM-JFR-Generic_ modules. -The JFR snapshots can be opened using either the File > Load action, or by -double-clicking the JFR Snapshots node and adding the snapshot into the JFR -repository, permanently. Please follow the documentation for your Java version to -create JFR snapshots. +The JFR snapshots can be opened using either the File > Load action, or by double-clicking the JFR Snapshots node and adding the snapshot into the JFR +repository, permanently. +Please follow the documentation for your Java version to create JFR snapshots. -The JFR viewer reads all JFR snapshots created from Java 7 onward, and presents the data in typical -VisualVM views familiar to the tool users. +The JFR viewer reads all JFR snapshots created from Java 7 onward, and presents the data in typical VisualVM views familiar to the tool users. ![](img/visualvm_jfr.png) @@ -109,7 +102,4 @@ usage, etc. * Recording tab - lists the recording settings and basic snapshot telemetry like number of events, total recording time, etc. -Note: the support of JDK Flight Recorder is currently experimental. Some advanced features like -analyzing JVM internals, showing event stack traces, or support for creating JFR -snapshots from live processes are not available in this preview version and will -be addressed incrementally in the following releases. +Note: The support of JDK Flight Recorder is currently experimental. Some advanced features like analyzing JVM internals, showing event stack traces, or support for creating JFR snapshots from live processes are not available in this preview version and will be addressed incrementally in the following releases. diff --git a/docs/tools/vscode/graalvm/README.md b/docs/tools/vscode/graalvm/README.md index 2f0ba532c380..486e7545d575 100644 --- a/docs/tools/vscode/graalvm/README.md +++ b/docs/tools/vscode/graalvm/README.md @@ -16,7 +16,7 @@ The extension is Technology Preview. - [Installation and Setup](#installation-and-setup) - [Java Development and Debugging](#java-development-and-debugging) - [Native Image Agent](#native-image-agent) -- [Native Image Debugger](#native-image-debugger) +- [Native Image Debugging](#native-image-debugging) - [Integration with VisualVM](#integration-with-visualvm) - [JavaScript and Node.js Debugging](#javascript-and-nodejs-debugging) - [Python Debugging](#python-debugging) @@ -125,7 +125,7 @@ The "Download & Install GraalVM" action is a preferable way, as it eliminates th ## Java Development and Debugging -To start developing or debugging Java applications, ensure GraalVM is used as your Java runtime in VS Code. +To start developing Java applications, ensure GraalVM is used as your Java runtime in VS Code. If the current path is not pointing to the GraalVM folder, go to the User Settings window and use the `netbeans.jdkhome` value in the _settings.json_ file. This configuration is then used to launch the Java Language Server. @@ -194,20 +194,37 @@ Once all possible execution paths have been executed, terminate the process. At Once the configuration for Native Image has been generated, follow the documentation on how to [generate a native image for a project](https://www.graalvm.org/reference-manual/native-image/#build-a-native-image) from the command line, or how to [build native images right from VS Code](../micronaut/README.md#generate-native-images-of-micronaut-projects). -## Native Image Debugger +## Native Image Debugging GraalVM Extension Pack for Java provides Java like debugging of platform native executables produced by [GraalVM Native Image](https://www.graalvm.org/reference-manual/native-image/). It is provided using the GNU Debugger (GDB) and via a new Run configuration named __Launch Native Image__. GraalVM Enterprise Edition is required as it produces full debug information for a native image. -> Note: This feature is experimental. It currently works only on Linux with GDB 7.11 or GDB 10.1+ due to known issue [#26139](https://sourceware.org/bugzilla/show_bug.cgi?id=26139) in GDB 8 and 9. +![Native Image debugging](images/ni_debugging.png) + +> Note: Native Image debugging requires `gdb` debugger (GDB 7.11 or GDB 10.1+), it currently works only on Linux. The feature is experimental. In order to debug native images of Java applications, it is necessary to build such images with debug information available. It can be done by providing following switches for the `native-image` builder: - `-g -O0` or - `-H:Debug=2 -H:Optimize=0`. -The resulting images will contain debug records in a format GDB understands. + +The resulting images will contain debug records in a format `gdb` debugger understands. + +### Debug Native Image “Real” Code + +Since recently you can attach the debugger to a Native Image process and step over the image “real” code. + +Attaching of debugger to a Native Image process is done via adding a configuration into the _launch.json_ file. + +1. Select **Native Image: Attach to Process** from the configurations autocompletion in _launch.json_. It generates the **Attach to Native Image** configuration. When that configuration is selected and executed, a list of running processes opens. +2. Select the running process that corresponds to the Native Image you intend to debug. +3. when the source file opens, start debugging: + ![Native Image debugging source code](images/NativeImageExecutableLocations.png) + +The step over the image “real” code” is mostly about UI differentiation of code which is compiled in the native image and which is not used. +The shaded code is not a part of the Native Image. ## Integration with VisualVM @@ -217,7 +234,7 @@ This brings the visual Java tooling to VS Code. ![VisualVM and VS Code Integration](images/vscode_visualvm.png) To get started, you need to get the latest stable GraalVM release using the **Download & Install GraalVM** action from the **Gr** activity view, as described in the [Installation and Setup](README.md#installation-and-setup) section. -Make sure the GraalVM is set as **active**. +Make sure the GraalVM is set as the **active** installation. Once a GraalVM installation is set as active, the Command Palette contains the following commands related to VisualVM: @@ -236,7 +253,7 @@ Follow these steps to start VisualVM automatically from within the VS Code: 4. Select the **Launch VisualVM & Java 8+ Application** launch configuration in the Run and Debug activity. Use the Start Debugging or Run Without Debugging action to start the current project. -While the project is starting, the Process node in VisualVM pane displays a project name with a "pid pending" label. +While the project is starting, the Process node in VisualVM pane displays the project name with a "pid pending" label. Once the project process starts, the Process node is updated to show its process ID (PID) and the action defined in step 3 is performed. > Note: This feature was introduced with the GraalVM 21.2.0 release. Please make sure to get the latest GraalVM Tools for Java extension from the VS Code Marketplace, preferably by downloading the [GraalVM Extension Pack for Java](https://marketplace.visualstudio.com/items?itemName=oracle-labs-graalvm.graalvm-pack). diff --git a/docs/tools/vscode/graalvm/images/NativeImageExecutableLocations.png b/docs/tools/vscode/graalvm/images/NativeImageExecutableLocations.png new file mode 100644 index 000000000000..e92439ccf895 Binary files /dev/null and b/docs/tools/vscode/graalvm/images/NativeImageExecutableLocations.png differ diff --git a/docs/tools/vscode/graalvm/images/ni_debugging.png b/docs/tools/vscode/graalvm/images/ni_debugging.png new file mode 100644 index 000000000000..50081069b88e Binary files /dev/null and b/docs/tools/vscode/graalvm/images/ni_debugging.png differ diff --git a/docs/tools/vscode/graalvm/visualvm-integration.md b/docs/tools/vscode/graalvm/visualvm-integration.md index 9e1a2abd036b..e94d3e8319c1 100644 --- a/docs/tools/vscode/graalvm/visualvm-integration.md +++ b/docs/tools/vscode/graalvm/visualvm-integration.md @@ -2,12 +2,12 @@ layout: docs toc_group: vscode link_title: VisualVM and VS Code Integration -permalink: /tools/vscode/visualvm-integration/ +permalink: /tools/vscode/graalvm/visualvm-integration/ --- -# VisualVM and VS Code Integration +## VisualVM and VS Code Integration -As of GraalVM 21.2.0, the GraalVM Tools for Java extension introduced a new feature in this version - the integration with VisualVM (https://visualvm.github.io), which is the all-in-one Java (and polyglot) monitoring and troubleshooting tool. +As of GraalVM 21.2.0, the GraalVM Tools for Java extension introduced a new feature in this version - the integration with [VisualVM](https://visualvm.github.io), which is the all-in-one Java (and polyglot) monitoring and troubleshooting tool. This brings the visual Java tooling to VS Code. ![VisualVM and VS Code Integration](images/vscode_visualvm.png) diff --git a/docs/tools/vscode/micronaut/README.md b/docs/tools/vscode/micronaut/README.md index d5e98099cd1b..d527c8835051 100644 --- a/docs/tools/vscode/micronaut/README.md +++ b/docs/tools/vscode/micronaut/README.md @@ -13,7 +13,7 @@ The extension is Technology Preview. The extension also enables the [Micronaut Launch](https://micronaut.io/launch/) application that allows you to create Micronaut projects through an interface inside VS Code, in addition to using the console CLI. There are, of course, other ways to create a new Micronaut application. If you provide a path to the [Micronaut CLI installation](https://micronaut-projects.github.io/micronaut-starter/latest/guide/#installation), you can create a project using the `mn` executable. If you prefer not to install the Micronaut CLI, and you are running on Linux or macOS, you can `curl` the project. Lastly, you can navigate to Micronaut Launch in a browser, create a new project, download it and open in VS Code. -In combination with the [GraalVM Tools for Java extension](https://marketplace.visualstudio.com/items?itemName=oracle-labs-graalvm.graalvm), you can run Micronaut projects on GraalVM, and debug them directly from the VS Code development environment with different debugging protocols enabled with the extension. This extension for Micronaut was also developed to help developers build native images directly from VS Code. +In combination with the [GraalVM Tools for Java extension](https://marketplace.visualstudio.com/items?itemName=oracle-labs-graalvm.graalvm), you can run Micronaut projects on GraalVM, and debug them directly from the VS Code development environment with different debugging protocols enabled with the extension. This extension for Micronaut was also developed to help developers build native images right from VS Code. #### Table of contents - [Installation and Setup](#installation-and-setup) @@ -22,10 +22,11 @@ In combination with the [GraalVM Tools for Java extension](https://marketplace.v - [Extension Settings](#extension-settings) - [Create Micronaut Project](#create-micronaut-project) - [Generate Native Images of Micronaut Projects](#generate-native-images-of-micronaut-projects) -- [Deploy Micronaut Projects](#deploy-micronaut-projects) -- [Feedback](#feedback) -- [Privacy Policy](#privacy-policy) -- [Known Issues](#known-issues) +- [Deploy Micronaut Projects to a Docker Registry](#deploy-micronaut-projects-to-a-docker-registry) +- [Deploy and Run Micronaut Applications in a Kubernetes Cluster](#deploy-and-run-micronaut-applications-in-a-kubernetes-cluster) +- [Preparation to Access a Kubernetes Cluster in Oracle Container Registry](#preparation-to-access-a-kubernetes-cluster-in-oracle-container-registry) +- [Deploy a Micronaut Application to OKE](#deploy-a-micronaut-application-to-oke) +- [Debug Micronaut Applications in a Kubernetes Cluster](#debug-micronaut-applications-in-a-kubernetes-cluster) ## Installation and Setup @@ -52,7 +53,7 @@ The GraalVM Tools for Micronaut extension provides: * code completion and navigation for Micronaut configuration (YAML) files and Java (available with [Apache NetBeans Language Server extension](https://marketplace.visualstudio.com/items?itemName=asf.apache-netbeans-java)). * ability to build Micronaut projects ahead-of-time into native images with GraalVM * __Run main with Continuous Mode__ CodeLens runs Micronaut project and reloads it automatically when source code is changed. It is not available as Debugger. - * __Launch Java: Continuous Mode__ is the name of the launch configuration. +* __Launch Java: Continuous Mode__ is the name of the launch configuration. ### Micronaut VS Code Commands @@ -107,14 +108,187 @@ That will run the `mvnw package -Dpackaging=native-image` job. For more details, continue reading to the [Micronaut documentation](https://guides.micronaut.io/micronaut-creating-first-graal-app/guide/index.html#creatingGraalImage). -## Deploy Micronaut Projects +## Deploy Micronaut Projects to a Docker Registry -The Micronaut support in VSCode also allows to build and deploy Docker image to a Docker Registry. -Use action View > Command Palette > Micronaut: Deploy... and select **dockerPush** to deploy dockerized Micronaut application or **dockerPushNative** to build and push docker with a native executable of Micronaut application. +The Micronaut support in VS Code allows to build and deploy Docker images to a Docker registry. +Use action **View** > **Command Palette** > **Micronaut: Deploy...** and select **dockerPush** to deploy a dockerized Micronaut application or **dockerPushNative** to build and push docker with a native executable of Micronaut application. ![Micronaut Deploy Commands](images/micronaut-deploy-commands.png) -Besides that, you can also push a Micronaut application or a native executable to a Docker Registry from the VS Code terminal window. A particular Docker Registry can be configured in the build, see the [Micronaut Deploying Application](https://micronaut-projects.github.io/micronaut-maven-plugin/latest/examples/deploy.html) documentation. +Besides that, you can also push a Micronaut application or a native executable to a Docker Registry from the VS Code Terminal window. +A particular Docker Registry can be configured in the build, see the [Micronaut Deploying Application](https://micronaut-projects.github.io/micronaut-maven-plugin/latest/examples/deploy.html) documentation. + +## Deploy and Run Micronaut Applications in a Kubernetes Cluster + +GraalVM Tools for Micronaut Extension added support for working with Kubernetes clusters based on Microsofts’s [Visual Studio Code Kubernetes Tools](https://marketplace.visualstudio.com/items?itemName=ms-kubernetes-tools.vscode-kubernetes-tools). +It is now possible to deploy, run and debug a Micronaut application in a Kubernetes cluster from VS Code. + +This guide is focused on and tested with Oracle Container Engine for Kubernetes (OKE)](https://www.oracle.com/uk/cloud-native/container-engine-kubernetes/) and Oracle Container Registry, but Kubernetes features should work in other environments. +OKE is a fully-managed, scalable, and highly available service that you can use to deploy your containerized applications to Oracle Cloud. + +This guide will walk you through the process of deploying a Micronaut application to OKE from VS Code and debugging it. + +### Prerequisites +- [Visual Studio Code Kubernetes Tools](https://marketplace.visualstudio.com/items?itemName=ms-kubernetes-tools.vscode-kubernetes-tools) +- [Docker](https://docs.docker.com/engine/reference/run/) +- [Oracle Cloud Account](https://www.oracle.com/uk/cloud/free/) +- [Access to Oracle Container Engine for Kubernetes (OKE)](https://oracle.github.io/learning-library/oci-library/oci-hol/OKE/workshops/freetier/index.html?lab=intro) + +## Preparation to Access a Kubernetes Cluster in Oracle Container Registry + +### Visual Studio Code Kubernetes Tools + +GraalVM Tools for Micronaut Extension uses `kubectl` provided by Microsoft's [Visual Studio Code Kubernetes Tools](https://marketplace.visualstudio.com/items?itemName=ms-kubernetes-tools.vscode-kubernetes-tools). +It has to be installed. + +Open Extensions tab, search for "Kubernetes" and install the one from Microsoft. +Once installed, you should see the Kubernetes icon in the left sidebar: +![Kubernetes extension installed](images/kubernetes_icon.png) + +### Oracle Cloud Account + +If you have not got an active Oracle Cloud account, create one by following this [link](https://docs.oracle.com/en/cloud/get-started/subscriptions-cloud/csgsg/get-oracle-com-account.html). + +### Access to Oracle Container Engine for Kubernetes (OKE) + +Supposedly, you have signed in to your Oracle Cloud account. +To be able to deploy Docker images to Oracle Container Registry, you need to setup the access to Oracle Container Engine for Kubernetes (OKE). + +**Step 1: Create a Kubernetes cluster in OCI** + +Using the Oracle Cloud Console, create a Kubernetes cluster with default settings using the *Quick Create* workflow: + +1. In the Oracle Cloud Console, open the navigation menu and click **Developer Services**. +2. Under Containers, click **Kubernetes Clusters (OKE)**. +3. Then click **Create Cluster**. + +For more information, check this [guide](https://docs.oracle.com/en-us/iaas/Content/ContEng/Tasks/contengcreatingclusterusingoke_topic-Using_the_Console_to_create_a_Quick_Cluster_with_Default_Settings.htm). + +**Step 2: Set up access to Kubernetes cluster** + +You can access your Kubernetes cluster and manage it using `kubectl`. +The `kubectl` command-line tool must be configured to communicate with your cluster. +To do that you have to set up a Kubernetes configuration file, _kubeconfig_. +The kubeconfig file (by default stored and can be found in the _$HOME/.kube/config_) provides the necessary details to access the cluster. + +See the [Setting Up Local Access to Clusters](https://docs.oracle.com/en-us/iaas/Content/ContEng/Tasks/contengdownloadkubeconfigfile.htm#localdownload) guide for step-by-step instructions. + +### Log in to Docker + +To be able to dockerize your Micronaut project, push and pull images on a local machine, and deploy to Oracle Container Registry, you will need [Docker](https://docs.docker.com/engine/reference/run/). +To check whether [Docker](https://docs.docker.com/engine/reference/run/) is started and running on your computer, go to VS Code Terminal and type: `docker --help`. + +Next you need to login with Docker to your Oracle Container Registry. +Prepare following Oracle Cloud account credentials: + +- Oracle Cloud Infrastructure (OCI) tenancy name +- User email address used for your OCI account +- OCI authentification token +- OCI region key + +From VS Code Terminal window, log in using the following command: +```bash +docker login -u / -p .ocir.io +``` +For example, if your OCI region is US East (Ashburn), then the key will be `iad`, and the region endpoint will be `https://iad.ocir.io`. +The list of available regions and their keys is available [here](https://docs.oracle.com/en-us/iaas/Content/Registry/Concepts/registryprerequisites.htm). + +> NOTE: If the Docker registry is private you will need a Docker registry secret. + +This [guide](https://docs.oracle.com/en-us/iaas/Content/ContEng/Tasks/contengpullingimagesfromocir.htm) describes how to create a Docker registry secret and describes how to specify the image to pull from Oracle Cloud Infrastructure Registry (along with the Docker secret to use) during application deployment to a cluster you've created using OKE. + +### Specify the Location for Docker Image in Oracle Container Registry + +The location where to push your Docker image in Oracle Container Registry should be specified in the project configuration file. + +If you used Gradle to build your Micronaut project, open the _gradle.build_ file and update image location: + ```xml + dockerBuild { + images = [".ocir.io///:"] + } + ``` + +See, for example, this example project configuration: +![Docker image location](images/docker_image_location.png) + +## Deploy a Micronaut Application to OKE + +To deploy, run and debug a Micronaut application in Oracle Container Engine for Kubernetes (OKE), the following quick actions for Micronaut are available: + +![Kubernetes quick actions](images/k8s_quick_actions.png) + +You should start by creating a Kubernetes deployment file that will be applied at the deployment stage. + +1. Go to View > Command Palette, search for "Kubernetes" and invoke the **Micronaut: Create Kubernetes Deployment Resource** action. It will start the "Create Kubernetes Deployment File" process. + +2. Pick the Docker repository. Since you are using Oracle Container Registry, select **OCIR + region name**. For example: + + ![Pick Docker repository](images/pick_docker_repository.png) + +3. Provide your Docker image name and version: + + ![Provide Docker image name and version](images/provide_image_name_version.png) + + Currently, available images are not automatically detected, so you need to type it manually. + Grab the image location from _gradle.build_ or _pom.xml_ you specified in the **Specify the Location for Docker Image in Oracle Container Registry** step. + +4. Then you are prompted to select the namespace. Choose default: + + ![Select namespace](images/select_namespace.png) + +5. Lastly, select a secret for your container registry in OCI (needed only if the Docker registry is private, described in the **Preparation** > **Log in to Docker** section): + + ![Select a secret for Docker registry](images/select_secret.png) + + The `Deploy.yaml` will be created. It will look similar to the following: + + ![Deploy.yaml](images/deploy_yaml.png) + +Now you are ready to deploy your Micronaut application to OKE. + +1. Go to View > Command Palette, search for **Micronaut: Deploy to Kubernetes** action and invoke it. + You could have skipped steps 1-3 from above, but if no Kubernetes deployment file exists, VS Code will suggest you to create one at this step. + +2. Once you invoke the action, the Output window will open and the "Starting deploy of project" message will be printed. + +When you hit this action, the project is packaged with Gradle/Maven to a runnable JAR file, built into a Docker image. +Then Docker pushes this image to the OKE repository (Oracle Container Registry), by applying the _deploy.yaml_ script. +The Kubernetes extension starts port forwarding to connect to the server running in a Kubernetes cluster (`kubectl port-forward` forwards a local port to a port on the Pod). +A direct URL to access your Micronaut REST application from a browser is printed. +Read more on Kubernetes port forwarding [here](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/). + +All this can be tracked in the Output window. +If the deployment succeeds, you should see a similar status bar: + +![Kubernetes deploy status](images/k8s_deply_output.png) + +To otherwise check the deployment's status, run: +```bash +kubectl get deployment +``` + +You can work on other projects, deploy them to another Kubernetes clusters, and they will all be deployed and running from Oracle Container Registry. + +## Debug Micronaut Applications in a Kubernetes Cluster + +In addition to being able to deploy and run Micronaut applications in Kubernetes, you can also debug your Java application in a cluster directly from VS Code. + +> Note: To allow complete Java debugging experience, you need to ensure the [GraalVM Extension Pack for Java](https://marketplace.visualstudio.com/items?itemName=oracle-labs-graalvm.graalvm) is installed. It is not needed if you have installed [GraalVM Tools for Java Extension pack](https://marketplace.visualstudio.com/items?itemName=oracle-labs-graalvm.graalvm-pack), it already includes a full-fledged support for the Java and Micronaut. + +With the connection made to a local port (thanks to [Kubernetes port forwarding feature](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/)), you can use your local workstation to debug the application that is running in the Pod. +Having set some breakpoints in your applciation, do the following to start debugging: + +1. Go to View > Command Palette, search for **Micronaut: Debug in Kubernetes** action and invoke it. +2. Confirm port forwarding. First time you start debugging your application deployed in Kubernetes, a popup window will open in the right bottom corner asking to confirm port forwarding. This will setup a `JAVA_TOOLS_OPTIONS` environment variable in the deployment script file. +3. Then you will be prompted to choose a port forwarding session: + + ![Choose a port forwarding session](images/k8s_port_forwarding.png) + +4. Connect the Kubernetes extension to your Kubernetes cluster using **Set Kubeconfig** action. +5. Click on Kubernetes icon in the left sidebar and select the node you are developing. +6. Right-click invoke action Debug (**Attach using Java 8+**): + +![Attach a remote debugger](images/attach-remote-debugger.png) ### Feedback diff --git a/docs/tools/vscode/micronaut/images/attach-remote-debugger.png b/docs/tools/vscode/micronaut/images/attach-remote-debugger.png new file mode 100644 index 000000000000..ac87b17a31f5 Binary files /dev/null and b/docs/tools/vscode/micronaut/images/attach-remote-debugger.png differ diff --git a/docs/tools/vscode/micronaut/images/create_k8s_deployment.png b/docs/tools/vscode/micronaut/images/create_k8s_deployment.png new file mode 100644 index 000000000000..7ab68066f697 Binary files /dev/null and b/docs/tools/vscode/micronaut/images/create_k8s_deployment.png differ diff --git a/docs/tools/vscode/micronaut/images/deploy_yaml.png b/docs/tools/vscode/micronaut/images/deploy_yaml.png new file mode 100644 index 000000000000..b45e2adc0f44 Binary files /dev/null and b/docs/tools/vscode/micronaut/images/deploy_yaml.png differ diff --git a/docs/tools/vscode/micronaut/images/docker_image_location.png b/docs/tools/vscode/micronaut/images/docker_image_location.png new file mode 100644 index 000000000000..a7845fa01b07 Binary files /dev/null and b/docs/tools/vscode/micronaut/images/docker_image_location.png differ diff --git a/docs/tools/vscode/micronaut/images/k8s_deply_output.png b/docs/tools/vscode/micronaut/images/k8s_deply_output.png new file mode 100644 index 000000000000..054303a63f9c Binary files /dev/null and b/docs/tools/vscode/micronaut/images/k8s_deply_output.png differ diff --git a/docs/tools/vscode/micronaut/images/k8s_port_forwarding.png b/docs/tools/vscode/micronaut/images/k8s_port_forwarding.png new file mode 100644 index 000000000000..2a50ac97811c Binary files /dev/null and b/docs/tools/vscode/micronaut/images/k8s_port_forwarding.png differ diff --git a/docs/tools/vscode/micronaut/images/k8s_quick_actions.png b/docs/tools/vscode/micronaut/images/k8s_quick_actions.png new file mode 100644 index 000000000000..95f025983e7c Binary files /dev/null and b/docs/tools/vscode/micronaut/images/k8s_quick_actions.png differ diff --git a/docs/tools/vscode/micronaut/images/kubernetes_icon.png b/docs/tools/vscode/micronaut/images/kubernetes_icon.png new file mode 100644 index 000000000000..e8882ca67fd9 Binary files /dev/null and b/docs/tools/vscode/micronaut/images/kubernetes_icon.png differ diff --git a/docs/tools/vscode/micronaut/images/micronaut-deploy-commands.png b/docs/tools/vscode/micronaut/images/micronaut-deploy-commands.png new file mode 100644 index 000000000000..b4a66b7334ea Binary files /dev/null and b/docs/tools/vscode/micronaut/images/micronaut-deploy-commands.png differ diff --git a/docs/tools/vscode/micronaut/images/micronaut-vs-code-commands.png b/docs/tools/vscode/micronaut/images/micronaut-vs-code-commands.png index 85d3f35e2fa6..c7f8f9b26f78 100644 Binary files a/docs/tools/vscode/micronaut/images/micronaut-vs-code-commands.png and b/docs/tools/vscode/micronaut/images/micronaut-vs-code-commands.png differ diff --git a/docs/tools/vscode/micronaut/images/micronaut.png b/docs/tools/vscode/micronaut/images/micronaut.png new file mode 100644 index 000000000000..eee520451550 Binary files /dev/null and b/docs/tools/vscode/micronaut/images/micronaut.png differ diff --git a/docs/tools/vscode/micronaut/images/pick_docker_repository.png b/docs/tools/vscode/micronaut/images/pick_docker_repository.png new file mode 100644 index 000000000000..c4365343dc46 Binary files /dev/null and b/docs/tools/vscode/micronaut/images/pick_docker_repository.png differ diff --git a/docs/tools/vscode/micronaut/images/provide_image_name_version.png b/docs/tools/vscode/micronaut/images/provide_image_name_version.png new file mode 100644 index 000000000000..47fc1d2b4726 Binary files /dev/null and b/docs/tools/vscode/micronaut/images/provide_image_name_version.png differ diff --git a/docs/tools/vscode/micronaut/images/select_namespace.png b/docs/tools/vscode/micronaut/images/select_namespace.png new file mode 100644 index 000000000000..3f3496b5f911 Binary files /dev/null and b/docs/tools/vscode/micronaut/images/select_namespace.png differ diff --git a/docs/tools/vscode/micronaut/images/select_secret.png b/docs/tools/vscode/micronaut/images/select_secret.png new file mode 100644 index 000000000000..5e5279f2b50d Binary files /dev/null and b/docs/tools/vscode/micronaut/images/select_secret.png differ diff --git a/docs/tools/vscode/vscode.md b/docs/tools/vscode/vscode.md index a5dddceafd15..948adab0a8d2 100644 --- a/docs/tools/vscode/vscode.md +++ b/docs/tools/vscode/vscode.md @@ -12,13 +12,13 @@ VS Code is an integrated development environment that provides the embedded Gi The following extensions are available for download from Visual Studio Code Marketplace: -- [**GraalVM Tools for Java**](/tools/vscode/graalvm-extension/) provides a full-fledged support for the Java language and, additionally, enables a polyglot environment in VS Code, making it a comfortable and convenient integrated development environment to work with. +- [**GraalVM Tools for Java**](graalvm/README.md) provides a full-fledged support for the Java language and, additionally, enables a polyglot environment in VS Code, making it a comfortable and convenient integrated development environment to work with. Users can edit, run and debug either single-language applications written in any of the GraalVM-supported languages (Java, JS, Ruby, R, and Python), or polyglot applications without the need to install any other additional extensions. The extension also offers the installation wizard that allows to download and install GraalVM and its optional features directly from the user interface. Get the extension from [Visual Studio Code Marketplace](https://marketplace.visualstudio.com/items?itemName=oracle-labs-graalvm.graalvm). -- [**GraalVM Tools for Micronaut**](/tools/vscode/micronaut-extension/) provides full support for developing applications based on the [Micronaut framework](https://micronaut.io/). The extension also enables the [Micronaut Launch](https://micronaut.io/launch/) application that allows you to create Micronaut projects through an interface inside VS Code, in addition to using the console CLI. This extension is integrated with GraalVM to provide all Native Image capabilities. You can generate native images directly from VS Code, and deploy them to a Docker Registry. Get the extension from [Visual Studio Code Marketplace](https://marketplace.visualstudio.com/items?itemName=oracle-labs-graalvm.micronaut). +- [**GraalVM Tools for Micronaut**](micronaut/README.md) provides full support for developing applications based on the [Micronaut framework](https://micronaut.io/). The extension also enables the [Micronaut Launch](https://micronaut.io/launch/) application that allows you to create Micronaut projects through an interface inside VS Code, in addition to using the console CLI. This extension is integrated with GraalVM to provide all Native Image capabilities. You can generate native images directly from VS Code, and deploy them to a Docker Registry. Get the extension from [Visual Studio Code Marketplace](https://marketplace.visualstudio.com/items?itemName=oracle-labs-graalvm.micronaut). -- [**GraalVM Extension Pack for Java**](/tools/vscode/graalvm-extension-pack/) is a collection of extensions that helps users write, debug and test Java, JavaScript, Python, Ruby, R and polyglot applications running on GraalVM, either standalone or using the Micronaut framework. +- [**GraalVM Extension Pack for Java**](graalvm-pack/README.md) is a collection of extensions that helps users write, debug and test Java, JavaScript, Python, Ruby, R and polyglot applications running on GraalVM, either standalone or using the Micronaut framework. GraalVM Extension Pack for Java bundles [GraalVM Tools for Java](https://marketplace.visualstudio.com/items?itemName=oracle-labs-graalvm.graalvm), [GraalVM Tools for Micronaut](https://marketplace.visualstudio.com/items?itemName=oracle-labs-graalvm.micronaut), and [Apache NetBeans Language Server](https://marketplace.visualstudio.com/items?itemName=asf.apache-netbeans-java) extensions. Get the extension pack from [Visual Studio Code Marketplace](https://marketplace.visualstudio.com/items?itemName=oracle-labs-graalvm.graalvm-pack). As of GraalVM 21.2.0, the GraalVM Tools for Java extension introduced a new feature - the integration with VisualVM (https://visualvm.github.io), which is the all-in-one Java (and polyglot) monitoring and troubleshooting tool. diff --git a/espresso/ci_common/common.jsonnet b/espresso/ci_common/common.jsonnet index 8a2342c75db4..4c60f706718c 100644 --- a/espresso/ci_common/common.jsonnet +++ b/espresso/ci_common/common.jsonnet @@ -50,8 +50,8 @@ local benchmark_suites = ['dacapo', 'renaissance', 'scala-dacapo']; darwin: self.common + { environment+: { - // for compatibility with macOS Sierra - MACOSX_DEPLOYMENT_TARGET: '10.12', + // for compatibility with macOS High Sierra + MACOSX_DEPLOYMENT_TARGET: '10.13', }, capabilities: ['darwin', 'amd64'], }, diff --git a/espresso/mx.espresso/mx_espresso.py b/espresso/mx.espresso/mx_espresso.py index 879b402edc4b..4634a54c2393 100644 --- a/espresso/mx.espresso/mx_espresso.py +++ b/espresso/mx.espresso/mx_espresso.py @@ -129,7 +129,14 @@ def _espresso_gate_runner(args, tasks): break with open(generated_header, 'r') as generated_header_file: - generated_header_lines = generated_header_file.readlines() + generated_header_lines = [] + for line in generated_header_file.readlines(): + # Ignore definitions that are not needed for Espresso + if not line.startswith("typedef") or "(*Espresso_" in line or "__graal" in line or "(*graal_" in line: + generated_header_lines.append(line) + else: + newline = generated_header_lines.pop() # Remove newline before ignored declaration + assert newline == "\n" errors = errors or mx.update_file(committed_header, ''.join(committed_header_copyright + generated_header_lines), showDiff=True) @@ -166,6 +173,7 @@ def _espresso_gate_runner(args, tasks): '--language:java', '--tool:all', '-H:+EnableSignalAPI', + '-R:+EnableSignalHandling', '-R:+InstallSegfaultHandler', '--features=com.oracle.truffle.espresso.FinalizationFeature', ], diff --git a/espresso/mx.espresso/suite.py b/espresso/mx.espresso/suite.py index f45444818a1c..11d11e1368ed 100644 --- a/espresso/mx.espresso/suite.py +++ b/espresso/mx.espresso/suite.py @@ -23,7 +23,7 @@ suite = { "mxversion": "5.280.5", "name": "espresso", - "version" : "21.3.0", + "version" : "22.0.0", "release" : False, "groupId" : "org.graalvm.espresso", "url" : "https://www.graalvm.org/reference-manual/java-on-truffle/", @@ -121,6 +121,20 @@ "checkPackagePrefix": False, # java.lang.ref.PublicFinalReference }, + "com.oracle.truffle.espresso.jdk17": { + "subDir": "src", + "sourceDirs": ["src"], + "overlayTarget": "com.oracle.truffle.espresso", + "dependencies": [ + "com.oracle.truffle.espresso", + ], + "checkPackagePrefix": "false", + "multiReleaseJarVersion": "17", + "checkstyle": "com.oracle.truffle.espresso", + "javaCompliance": "17+", + }, + + "com.oracle.truffle.espresso.processor": { "subDir": "src", "sourceDirs": ["src"], diff --git a/espresso/src/com.oracle.truffle.espresso.jdk17/src/com/oracle/truffle/espresso/overlay/ReferenceSupport.java b/espresso/src/com.oracle.truffle.espresso.jdk17/src/com/oracle/truffle/espresso/overlay/ReferenceSupport.java new file mode 100644 index 000000000000..9800ede6ec92 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.jdk17/src/com/oracle/truffle/espresso/overlay/ReferenceSupport.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.truffle.espresso.overlay; + +import java.lang.ref.Reference; + +import com.oracle.truffle.espresso.runtime.StaticObject; + +public class ReferenceSupport { + public static boolean phantomReferenceRefersTo(Reference ref, StaticObject object) { + return ref.refersTo(object); + } + + public static boolean referenceRefersTo(Reference ref, StaticObject object) { + return ref.refersTo(object); + } +} diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/ErrorCodes.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/ErrorCodes.java index 7f1c44d8eea9..4b1e417b2650 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/ErrorCodes.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/ErrorCodes.java @@ -35,6 +35,7 @@ public final class ErrorCodes { public static final int INVALID_FRAMEID = 30; public static final int OPAQUE_FRAME = 32; public static final int INVALID_SLOT = 35; + public static final int INVALID_MODULE = 42; public static final int INVALID_CLASS_FORMAT = 60; public static final int FAILS_VERIFICATION = 62; public static final int ADD_METHOD_NOT_IMPLEMENTED = 63; diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/JDWPContext.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/JDWPContext.java index bf50a832b036..beb6293c1b81 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/JDWPContext.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/JDWPContext.java @@ -497,4 +497,21 @@ public interface JDWPContext { * @return the instrumentable delegate node */ Node getInstrumentableNode(RootNode rootNode); + + /** + * Tests if the guest object is a member of the klass. + * + * @param guestObject the guest object + * @param klass the class + * @return true is guest object is a member of the klass + */ + boolean isMemberOf(Object guestObject, KlassRef klass); + + /** + * Returns all defined modules. + * + * @return all modules + */ + ModuleRef[] getAllModulesRefs(); + } diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/KlassRef.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/KlassRef.java index c78f0c8ce3ad..4af2cd86c195 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/KlassRef.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/KlassRef.java @@ -181,4 +181,11 @@ public interface KlassRef { * @return the extension */ String getSourceDebugExtension(); + + /** + * Returns the Module reference of the class. + * + * @return the module reference + */ + ModuleRef getModule(); } diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/ModuleRef.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/ModuleRef.java new file mode 100644 index 000000000000..1bde578b8058 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/ModuleRef.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.jdwp.api; + +/** + * Interface representing a module reference in the VM. + */ +public interface ModuleRef { + + ModuleRef[] EMPTY_ARRAY = new ModuleRef[0]; + + /** + * Returns the name of the module. + * + * @return module name + */ + String jdwpName(); + + /** + * Returns the guest object representing the defining classloader of the module. + * + * @return the defining classloader + */ + Object classLoader(); +} diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/VMEventListener.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/VMEventListener.java index bfd654e7dda2..0dad3f93ef25 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/VMEventListener.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/VMEventListener.java @@ -37,7 +37,7 @@ public interface VMEventListener extends VMListener { void breakpointHit(BreakpointInfo info, CallFrame frame, Object currentThread); - void vmDied(); + boolean vmDied(); void addClassUnloadRequestId(int id); @@ -47,7 +47,7 @@ public interface VMEventListener extends VMListener { void addVMStartRequest(int id); - void addVMDeathRequest(int id); + void addVMDeathRequest(int id, byte suspendPolicy); void addClassPrepareRequest(ClassPrepareRequest request); diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/VMEventListenerImpl.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/VMEventListenerImpl.java index 78a4963c1088..75b298918783 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/VMEventListenerImpl.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/VMEventListenerImpl.java @@ -78,6 +78,7 @@ public final class VMEventListenerImpl implements VMEventListener { private byte threadStartSuspendPolicy; private byte threadDeathSuspendPolicy; private int vmDeathRequestId; + private byte vmDeathSuspendPolicy = SuspendStrategy.NONE; private int vmStartRequestId; private final List heldEvents = new ArrayList<>(); private final Map currentContendedMonitor = new HashMap<>(); @@ -891,17 +892,27 @@ public void vmStarted(boolean suspend) { } @Override - public void vmDied() { + public boolean vmDied() { if (connection == null) { - return; + return false; } PacketStream stream = new PacketStream().commandPacket().commandSet(64).command(100); - stream.writeByte(SuspendStrategy.NONE); - stream.writeInt(1); + stream.writeByte(vmDeathSuspendPolicy); + if (vmDeathRequestId != 0) { + stream.writeInt(2); + // requested event + stream.writeByte(RequestedJDWPEvents.VM_DEATH); + stream.writeInt(vmDeathRequestId); + // automatic event + } else { + // only automatic event to send + stream.writeInt(1); + } stream.writeByte(RequestedJDWPEvents.VM_DEATH); - stream.writeInt(vmDeathRequestId != -1 ? vmDeathRequestId : 0); + stream.writeInt(0); // don't queue this packet, send immediately connection.sendVMDied(stream); + return vmDeathSuspendPolicy != SuspendStrategy.NONE; } @Override @@ -937,13 +948,14 @@ public void removeThreadDiedRequestId() { } @Override - public void addVMDeathRequest(int id) { - this.vmStartRequestId = id; + public void addVMDeathRequest(int id, byte suspendPolicy) { + this.vmDeathRequestId = id; + this.vmDeathSuspendPolicy = suspendPolicy; } @Override public void addVMStartRequest(int id) { - this.vmDeathRequestId = id; + this.vmStartRequestId = id; } @Override diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerConnection.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerConnection.java index 500ed5c06c73..62f975da6cdf 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerConnection.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerConnection.java @@ -286,6 +286,9 @@ private void processPacket(Packet packet) { case JDWP.VirtualMachine.INSTANCE_COUNTS.ID: result = JDWP.VirtualMachine.INSTANCE_COUNTS.createReply(packet); break; + case JDWP.VirtualMachine.ALL_MODULES.ID: + result = JDWP.VirtualMachine.ALL_MODULES.createReply(packet, context); + break; default: break; } @@ -347,6 +350,9 @@ private void processPacket(Packet packet) { case JDWP.ReferenceType.CONSTANT_POOL.ID: result = JDWP.ReferenceType.CONSTANT_POOL.createReply(packet, context); break; + case JDWP.ReferenceType.MODULE.ID: + result = JDWP.ReferenceType.MODULE.createReply(packet, context); + break; } break; } @@ -571,6 +577,19 @@ private void processPacket(Packet packet) { } break; } + case JDWP.ModuleReference.ID: { + switch (packet.cmd) { + case JDWP.ModuleReference.NAME.ID: + result = JDWP.ModuleReference.NAME.createReply(packet, context); + break; + case JDWP.ModuleReference.CLASSLOADER.ID: + result = JDWP.ModuleReference.CLASSLOADER.createReply(packet, context); + break; + default: + break; + } + break; + } case JDWP.Event.ID: { switch (packet.cmd) { case JDWP.Event.COMPOSITE.ID: @@ -587,8 +606,16 @@ private void processPacket(Packet packet) { } handleReply(packet, result); } catch (Throwable t) { - JDWP.LOGGER.warning(() -> "[Internal error]: " + t.getClass()); - JDWP.LOGGER.throwing(DebuggerConnection.class.getName(), "processPacket", t); + if (entered) { + // we can only use the Truffle logger if we were able to enter the context + JDWP.LOGGER.warning(() -> "[Internal error]"); + JDWP.LOGGER.throwing(DebuggerConnection.class.getName(), "processPacket", t); + } else { + // Checkstyle: stop allow error output + System.out.println("[internal error]: " + t.getMessage()); + t.printStackTrace(); + // Checkstyle: resume allow error output + } PacketStream reply = new PacketStream().replyPacket().id(packet.id); reply.errorCode(ErrorCodes.INTERNAL); handleReply(packet, new CommandResult(reply)); diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerController.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerController.java index eb4e8c8ffa6b..746f20f27ec6 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerController.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerController.java @@ -467,7 +467,10 @@ public void disposeDebugger(boolean prepareReconnect) { if (!prepareReconnect) { // OK, we're closing down the context which is equivalent // to a dead VM from a JDWP client point of view - eventListener.vmDied(); + if (eventListener.vmDied()) { + // we're asked to suspend + suspend(null, context.asGuestThread(Thread.currentThread()), SuspendStrategy.EVENT_THREAD, Collections.emptyList(), null, false); + } } // Creating a new thread, because the reset method // will interrupt all active jdwp threads, which might diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java index c5cc5a4eb9ee..5218f9db540c 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java @@ -22,9 +22,6 @@ */ package com.oracle.truffle.espresso.jdwp.impl; -import static com.oracle.truffle.espresso.jdwp.api.TagConstants.BOOLEAN; -import static com.oracle.truffle.espresso.jdwp.api.TagConstants.VOID; - import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; @@ -43,6 +40,7 @@ import com.oracle.truffle.espresso.jdwp.api.LineNumberTableRef; import com.oracle.truffle.espresso.jdwp.api.LocalRef; import com.oracle.truffle.espresso.jdwp.api.MethodRef; +import com.oracle.truffle.espresso.jdwp.api.ModuleRef; import com.oracle.truffle.espresso.jdwp.api.MonitorStackInfo; import com.oracle.truffle.espresso.jdwp.api.RedefineInfo; import com.oracle.truffle.espresso.jdwp.api.TagConstants; @@ -465,6 +463,21 @@ static CommandResult createReply(Packet packet) { return new CommandResult(reply); } } + + static class ALL_MODULES { + public static final int ID = 22; + + static CommandResult createReply(Packet packet, JDWPContext context) { + PacketStream reply = new PacketStream().replyPacket().id(packet.id); + + ModuleRef[] moduleRefs = context.getAllModulesRefs(); + reply.writeInt(moduleRefs.length); + for (ModuleRef moduleRef : moduleRefs) { + reply.writeLong(context.getIds().getIdAsLong(moduleRef)); + } + return new CommandResult(reply); + } + } } static class ReferenceType { @@ -976,6 +989,35 @@ static CommandResult createReply(Packet packet, JDWPContext context) { return new CommandResult(reply); } } + + static class MODULE { + + public static final int ID = 19; + + static CommandResult createReply(Packet packet, JDWPContext context) { + PacketStream input = new PacketStream(packet); + PacketStream reply = new PacketStream().replyPacket().id(packet.id); + + long typeId = input.readLong(); + KlassRef klass = verifyRefType(typeId, reply, context); + + if (klass == null) { + // input could be a classObjectId + Object object = context.getIds().fromId((int) typeId); + klass = context.getReflectedType(object); + } + + if (klass == null) { + return new CommandResult(reply); + } + + ModuleRef module = klass.getModule(); + long moduleID = context.getIds().getIdAsLong(module); + reply.writeLong(moduleID); + + return new CommandResult(reply); + } + } } static class ClassType { @@ -1075,6 +1117,22 @@ static CommandResult createReply(Packet packet, DebuggerController controller, D return new CommandResult(reply); } + // check that method is member of the class type or a super class + KlassRef declaringKlass = method.getDeclaringKlass(); + KlassRef checkedKlass = klass; + boolean isMember = false; + while (checkedKlass != null) { + if (checkedKlass == declaringKlass) { + isMember = true; + break; + } + checkedKlass = checkedKlass.getSuperClass(); + } + if (!isMember) { + reply.errorCode(ErrorCodes.INVALID_METHODID); + return new CommandResult(reply); + } + LOGGER.fine(() -> "trying to invoke static method: " + method.getNameAsString()); int arguments = input.readInt(); @@ -1105,10 +1163,28 @@ public Object call() { new Thread(new Runnable() { @Override public void run() { - ThreadJob.JobResult result = job.getResult(); - writeMethodResult(reply, context, result); + boolean entered = false; CommandResult commandResult = new CommandResult(reply); - connection.handleReply(packet, commandResult); + try { + ThreadJob.JobResult result = job.getResult(); + writeMethodResult(reply, context, result); + } catch (Throwable t) { + entered = controller.enterTruffleContext(); + reply.errorCode(ErrorCodes.INTERNAL); + // Checkstyle: stop allow error output + if (entered) { + LOGGER.warning(() -> "Internal Espresso error: " + t); + } else { + System.err.println("Internal Espresso error: " + t.getMessage()); + } + t.printStackTrace(); + // Checkstyle: resume allow error output + } finally { + connection.handleReply(packet, commandResult); + if (entered) { + controller.leaveTruffleContext(); + } + } } }).start(); } catch (Throwable t) { @@ -1239,6 +1315,11 @@ static CommandResult createReply(Packet packet, DebuggerController controller, D return new CommandResult(reply); } + if (method.getDeclaringKlass() != itf) { + reply.errorCode(ErrorCodes.INVALID_METHODID); + return new CommandResult(reply); + } + LOGGER.fine(() -> "trying to invoke interface method: " + method.getNameAsString()); int arguments = input.readInt(); @@ -1269,10 +1350,28 @@ public Object call() throws Exception { new Thread(new Runnable() { @Override public void run() { - ThreadJob.JobResult result = job.getResult(); - writeMethodResult(reply, context, result); + boolean entered = false; CommandResult commandResult = new CommandResult(reply); - connection.handleReply(packet, commandResult); + try { + ThreadJob.JobResult result = job.getResult(); + writeMethodResult(reply, context, result); + } catch (Throwable t) { + entered = controller.enterTruffleContext(); + reply.errorCode(ErrorCodes.INTERNAL); + // Checkstyle: stop allow error output + if (entered) { + LOGGER.warning(() -> "Internal Espresso error: " + t); + } else { + System.err.println("Internal Espresso error: " + t.getMessage()); + } + t.printStackTrace(); + // Checkstyle: resume allow error output + } finally { + connection.handleReply(packet, commandResult); + if (entered) { + controller.leaveTruffleContext(); + } + } } }).start(); } catch (Throwable t) { @@ -1728,6 +1827,11 @@ static CommandResult createReply(Packet packet, DebuggerController controller, D return new CommandResult(reply); } + if (!context.isMemberOf(callee, method.getDeclaringKlass())) { + reply.errorCode(ErrorCodes.INVALID_METHODID); + return new CommandResult(reply); + } + LOGGER.fine("trying to invoke method: " + method.getNameAsString()); int invocationOptions = input.readInt(); @@ -1749,10 +1853,28 @@ public Object call() throws Exception { new Thread(new Runnable() { @Override public void run() { - ThreadJob.JobResult result = job.getResult(); - writeMethodResult(reply, context, result); + boolean entered = false; CommandResult commandResult = new CommandResult(reply); - connection.handleReply(packet, commandResult); + try { + ThreadJob.JobResult result = job.getResult(); + writeMethodResult(reply, context, result); + } catch (Throwable t) { + entered = controller.enterTruffleContext(); + reply.errorCode(ErrorCodes.INTERNAL); + // Checkstyle: stop allow error output + if (entered) { + LOGGER.warning(() -> "Internal Espresso error: " + t); + } else { + System.err.println("Internal Espresso error: " + t.getMessage()); + } + t.printStackTrace(); + // Checkstyle: resume allow error output + } finally { + connection.handleReply(packet, commandResult); + if (entered) { + controller.leaveTruffleContext(); + } + } } }).start(); } catch (Throwable t) { @@ -2516,7 +2638,7 @@ static CommandResult createReply(Packet packet, JDWPContext context) { private static void setArrayValues(JDWPContext context, PacketStream input, int index, int values, Object array, byte tag) { for (int i = index; i < index + values; i++) { switch (tag) { - case BOOLEAN: + case TagConstants.BOOLEAN: boolean bool = input.readBoolean(); byte[] boolArray = context.getUnboxedArray(array); boolArray[i] = bool ? (byte) 1 : (byte) 0; @@ -2651,6 +2773,9 @@ static CommandResult createReply(Packet packet, JDWPContext context) { } byte sigbyte = input.readByte(); + if (sigbyte == TagConstants.OBJECT) { + sigbyte = context.getTag(value); + } writeValue(sigbyte, value, reply, true, context); } @@ -2786,6 +2911,55 @@ static CommandResult createReply(Packet packet, JDWPContext context) { } } + static class ModuleReference { + public static final int ID = 18; + + static class NAME { + + public static final int ID = 1; + + public static CommandResult createReply(Packet packet, JDWPContext context) { + PacketStream input = new PacketStream(packet); + PacketStream reply = new PacketStream().replyPacket().id(packet.id); + + long moduleId = input.readLong(); + ModuleRef module = verifyModule(moduleId, reply, context); + + if (module == null) { + return new CommandResult(reply); + } + + reply.writeString(module.jdwpName()); + return new CommandResult(reply); + } + } + + static class CLASSLOADER { + + public static final int ID = 2; + + public static CommandResult createReply(Packet packet, JDWPContext context) { + PacketStream input = new PacketStream(packet); + PacketStream reply = new PacketStream().replyPacket().id(packet.id); + + long moduleId = input.readLong(); + ModuleRef module = verifyModule(moduleId, reply, context); + + if (module == null) { + return new CommandResult(reply); + } + + Object loader = module.classLoader(); + if (loader == null || loader == context.getNullObject()) { // system class loader + reply.writeLong(0); + } else { + reply.writeLong(context.getIds().getIdAsLong(loader)); + } + return new CommandResult(reply); + } + } + } + static class Event { public static final int ID = 64; @@ -2860,9 +3034,9 @@ private static Object readValue(byte valueKind, PacketStream input, JDWPContext private static Object readValue(PacketStream input, JDWPContext context) { byte valueKind = input.readByte(); switch (valueKind) { - case VOID: + case TagConstants.VOID: return Void.TYPE; - case BOOLEAN: + case TagConstants.BOOLEAN: return input.readBoolean(); case TagConstants.BYTE: return input.readByte(); @@ -2896,7 +3070,7 @@ public static void writeValue(byte tag, Object value, PacketStream reply, boolea reply.writeByte(tag); } switch (tag) { - case BOOLEAN: + case TagConstants.BOOLEAN: if (value.getClass() == Long.class) { long unboxed = (long) value; reply.writeBoolean(unboxed > 0 ? true : false); @@ -2974,31 +3148,24 @@ public static void writeValue(byte tag, Object value, PacketStream reply, boolea } private static void writeMethodResult(PacketStream reply, JDWPContext context, ThreadJob.JobResult result) { - try { - if (result.getException() != null) { - LOGGER.fine(() -> "method threw exception"); - reply.writeByte(TagConstants.OBJECT); - reply.writeLong(0); - reply.writeByte(TagConstants.OBJECT); - Object guestException = context.getGuestException(result.getException()); - reply.writeLong(context.getIds().getIdAsLong(guestException)); - } else { - Object value = context.toGuest(result.getResult()); - if (value != null) { - byte tag = context.getTag(value); - writeValue(tag, value, reply, true, context); - } else { // return value is null - reply.writeByte(TagConstants.OBJECT); - reply.writeLong(0); - } - // no exception, so zero object ID + if (result.getException() != null) { + reply.writeByte(TagConstants.OBJECT); + reply.writeLong(0); + reply.writeByte(TagConstants.OBJECT); + Object guestException = context.getGuestException(result.getException()); + reply.writeLong(context.getIds().getIdAsLong(guestException)); + } else { + Object value = context.toGuest(result.getResult()); + if (value != null) { + byte tag = context.getTag(value); + writeValue(tag, value, reply, true, context); + } else { // return value is null reply.writeByte(TagConstants.OBJECT); reply.writeLong(0); } - } catch (Throwable t) { - LOGGER.warning(() -> "Internal Espresso error: " + t); - LOGGER.throwing(JDWP.class.getName(), "writeMethodResult", t); - reply.errorCode(ErrorCodes.INTERNAL); + // no exception, so zero object ID + reply.writeByte(TagConstants.OBJECT); + reply.writeLong(0); } } @@ -3027,6 +3194,17 @@ private static KlassRef verifyRefType(long refTypeId, PacketStream reply, JDWPCo return klass; } + private static ModuleRef verifyModule(long moduleId, PacketStream reply, JDWPContext context) { + ModuleRef module; + try { + module = (ModuleRef) context.getIds().fromId((int) moduleId); + } catch (ClassCastException ex) { + reply.errorCode(ErrorCodes.INVALID_MODULE); + return null; + } + return module; + } + private static FieldRef verifyFieldRef(long fieldId, PacketStream reply, JDWPContext context) { FieldRef field; try { diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWPInstrument.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWPInstrument.java index b74b1bf46b9a..149b6d000823 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWPInstrument.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWPInstrument.java @@ -58,11 +58,6 @@ protected void onCreate(TruffleInstrument.Env instrumentEnv) { } public void reset(boolean prepareForReconnect) { - // close the connection to the debugger - if (connection != null) { - connection.close(); - } - // stop all running jdwp threads in an orderly fashion for (Thread activeThread : activeThreads) { activeThread.interrupt(); @@ -93,6 +88,11 @@ public void reset(boolean prepareForReconnect) { // resume all threads controller.resumeAll(true); + // close the connection to the debugger + if (connection != null) { + connection.close(); + } + if (prepareForReconnect) { // replace the controller instance controller.reInitialize(); diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/RequestedJDWPEvents.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/RequestedJDWPEvents.java index 324fb472edfc..c77e71fb4a62 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/RequestedJDWPEvents.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/RequestedJDWPEvents.java @@ -168,8 +168,8 @@ public CommandResult registerEvent(Packet packet, Commands callback) { case VM_START: // no debuggers should ask for this event eventListener.addVMStartRequest(packet.id); break; - case VM_DEATH: // no debuggers should request this event - eventListener.addVMDeathRequest(packet.id); + case VM_DEATH: + eventListener.addVMDeathRequest(packet.id, suspendPolicy); break; case MONITOR_CONTENDED_ENTER: eventListener.addMonitorContendedEnterRequest(packet.id, filter); diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/SocketConnection.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/SocketConnection.java index 68a266fcd276..e89797f29ead 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/SocketConnection.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/SocketConnection.java @@ -51,10 +51,25 @@ public final class SocketConnection implements Runnable { } public void close() throws IOException { + // send outstanding packets before closing + while (!queue.isEmpty()) { + for (PacketStream packetStream : queue) { + byte[] shipment = packetStream.prepareForShipment(); + try { + writePacket(shipment); + } catch (ConnectionClosedException e) { + JDWP.LOGGER.finest("connection was closed when trying to flush queue"); + } + } + } + socketOutput.flush(); + synchronized (closeLock) { if (closed) { return; } + JDWP.LOGGER.fine("closing socket now"); + if (serverSocket != null) { serverSocket.close(); } diff --git a/espresso/src/com.oracle.truffle.espresso.libespresso/src/com/oracle/truffle/espresso/libespresso/LibEspresso.java b/espresso/src/com.oracle.truffle.espresso.libespresso/src/com/oracle/truffle/espresso/libespresso/LibEspresso.java index 1be98ce24511..8818f8520fac 100644 --- a/espresso/src/com.oracle.truffle.espresso.libespresso/src/com/oracle/truffle/espresso/libespresso/LibEspresso.java +++ b/espresso/src/com.oracle.truffle.espresso.libespresso/src/com/oracle/truffle/espresso/libespresso/LibEspresso.java @@ -27,6 +27,7 @@ import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.ObjectHandle; import org.graalvm.nativeimage.ObjectHandles; +import org.graalvm.nativeimage.VMRuntime; import org.graalvm.nativeimage.c.function.CEntryPoint; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Value; @@ -61,6 +62,7 @@ static int createJavaVM(@SuppressWarnings("unused") IsolateThread thread, JNIJav if (result != JNIErrors.JNI_OK()) { return result; } + VMRuntime.initialize(); // Use the nuclear option for System.exit builder.option("java.ExitHost", "true"); builder.option("java.EnableSignals", "true"); diff --git a/espresso/src/com.oracle.truffle.espresso.mokapot/include/libespresso_dynamic.h b/espresso/src/com.oracle.truffle.espresso.mokapot/include/libespresso_dynamic.h index 3ad28a709a59..d86a18b168cf 100644 --- a/espresso/src/com.oracle.truffle.espresso.mokapot/include/libespresso_dynamic.h +++ b/espresso/src/com.oracle.truffle.espresso.mokapot/include/libespresso_dynamic.h @@ -42,8 +42,6 @@ typedef int (*Espresso_CloseContext_fn_t)(graal_isolatethread_t* thread, struct typedef void (*Espresso_Exit_fn_t)(graal_isolatethread_t* thread, struct JavaVM_* javaVM); -typedef void (*vmLocatorSymbol_fn_t)(graal_isolatethread_t* thread); - #if defined(__cplusplus) } #endif diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoLanguage.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoLanguage.java index b6f055f118d4..d3f9d3dd0325 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoLanguage.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoLanguage.java @@ -25,14 +25,12 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Level; -import com.oracle.truffle.api.ContextThreadLocal; -import com.oracle.truffle.espresso.runtime.EspressoThreadLocalState; import org.graalvm.home.Version; import org.graalvm.options.OptionDescriptors; import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.ContextThreadLocal; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.TruffleLanguage.Registration; import com.oracle.truffle.api.instrumentation.ProvidedTags; @@ -57,6 +55,7 @@ import com.oracle.truffle.espresso.nodes.interop.GetBindingsNode; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.EspressoExitException; +import com.oracle.truffle.espresso.runtime.EspressoThreadLocalState; import com.oracle.truffle.espresso.runtime.StaticObject; import com.oracle.truffle.espresso.runtime.StaticObject.StaticObjectFactory; import com.oracle.truffle.espresso.substitutions.Substitutions; @@ -64,7 +63,6 @@ @Registration(id = EspressoLanguage.ID, // name = EspressoLanguage.NAME, // implementationName = EspressoLanguage.IMPLEMENTATION_NAME, // - version = EspressoLanguage.VERSION, // contextPolicy = TruffleLanguage.ContextPolicy.EXCLUSIVE, // dependentLanguages = {"nfi", "llvm"}) @ProvidedTags({StandardTags.RootTag.class, StandardTags.RootBodyTag.class, StandardTags.StatementTag.class}) @@ -73,7 +71,6 @@ public final class EspressoLanguage extends TruffleLanguage { public static final String ID = "java"; public static final String NAME = "Java"; public static final String IMPLEMENTATION_NAME = "Espresso"; - public static final String VERSION = "1.8|11"; // Espresso VM info public static final String VM_SPECIFICATION_NAME = "Java Virtual Machine Specification"; @@ -180,15 +177,15 @@ protected CallTarget parse(final ParsingRequest request) throws Exception { String contents = request.getSource().getCharacters().toString(); if (DestroyVMNode.EVAL_NAME.equals(contents)) { RootNode node = new DestroyVMNode(this); - return Truffle.getRuntime().createCallTarget(node); + return node.getCallTarget(); } if (ExitCodeNode.EVAL_NAME.equals(contents)) { RootNode node = new ExitCodeNode(this); - return Truffle.getRuntime().createCallTarget(node); + return node.getCallTarget(); } if (GetBindingsNode.EVAL_NAME.equals(contents)) { RootNode node = new GetBindingsNode(this); - return Truffle.getRuntime().createCallTarget(node); + return node.getCallTarget(); } throw new UnsupportedOperationException("Unsupported operation. Use the language bindings to load classes e.g. context.getBindings(\"" + ID + "\").getMember(\"java.lang.Integer\")"); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoOptions.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoOptions.java index cf2631d04a72..a3569aa7cd9d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoOptions.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoOptions.java @@ -236,6 +236,10 @@ public VerifyMode apply(String s) { category = OptionCategory.EXPERT, stability = OptionStability.STABLE) // public static final OptionKey LivenessAnalysis = new OptionKey<>(false); + @Option(help = "Enable Class Hierarchy Analysis, which optimizes instanceof checks and virtual method calls by keeping track of descendants of a given class or interface.", // + category = OptionCategory.EXPERT, stability = OptionStability.EXPERIMENTAL) // + public static final OptionKey CHA = new OptionKey<>(false); + private static final OptionType JDWP_OPTIONS_OPTION_TYPE = new OptionType<>("JDWPOptions", new Function() { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/hierarchy/ClassHierarchyOracle.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/hierarchy/ClassHierarchyOracle.java new file mode 100644 index 000000000000..95cbb49fbc7c --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/hierarchy/ClassHierarchyOracle.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.truffle.espresso.analysis.hierarchy; + +import com.oracle.truffle.espresso.impl.ObjectKlass; +import com.oracle.truffle.espresso.runtime.EspressoContext; + +/** + * {@code ClassHierarchyOracle} provides information about class hierarchy in the guest code, + * evolving as new classes are loaded. The oracle is safe, i.e. its answers never cause incorrect + * optimizations, but not necessarily precise (e.g. may not detect an effectively leaf type). + *

    + * The oracle is only valid within an {@link EspressoContext}. + */ +public interface ClassHierarchyOracle { + final class LeafTypeAssumptionAccessor { + protected LeafTypeAssumptionAccessor() { + } + } + + /** + * Must be called to initialize {@code leafTypeAssumption} of {@code newKlass}. In addition, it + * communicates to the oracle that a new klass has been created and its ancestors are no longer + * leaves. + * + * @param newKlass -- newly created class + * @return the assumption, indicating whether the class is a leaf in class hierarchy. + */ + LeafTypeAssumption createAssumptionForNewKlass(ObjectKlass newKlass); + + /** + * @return the assumption, valid iff {@code klass} is a leaf in class hierarchy. Automatically + * invalidated in {@link #createAssumptionForNewKlass(ObjectKlass)} when a child of + * {@code klass} is created. + */ + LeafTypeAssumption isLeafClass(ObjectKlass klass); +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/hierarchy/DefaultClassHierarchyOracle.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/hierarchy/DefaultClassHierarchyOracle.java new file mode 100644 index 000000000000..948c5222cac1 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/hierarchy/DefaultClassHierarchyOracle.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.truffle.espresso.analysis.hierarchy; + +import com.oracle.truffle.espresso.impl.ObjectKlass; + +/** + * Computes the classes that are effectively final by keeping track of currently loaded classes. To + * compute currently leaf classes, it creates {@code leafTypeAssumption} in the {@link ObjectKlass} + * constructor and invalidates it when a descendant of this class is initialized. + */ +public class DefaultClassHierarchyOracle extends NoOpClassHierarchyOracle implements ClassHierarchyOracle { + @Override + public LeafTypeAssumption createAssumptionForNewKlass(ObjectKlass newKlass) { + markAncestorsAsNonLeaf(newKlass); + + if (newKlass.isFinalFlagSet()) { + return FinalIsAlwaysLeaf; + } + if (newKlass.isAbstract() || newKlass.isInterface()) { + return NotLeaf; + } + return new LeafTypeAssumptionImpl(newKlass); + } + + private static void markAncestorsAsNonLeaf(ObjectKlass newClass) { + ObjectKlass currentParent = newClass.getSuperKlass(); + while (currentParent != null && currentParent.getLeafTypeAssumption(assumptionAccessor).getAssumption().isValid()) { + currentParent.getLeafTypeAssumption(assumptionAccessor).getAssumption().invalidate(); + currentParent = currentParent.getSuperKlass(); + } + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/hierarchy/LeafTypeAssumption.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/hierarchy/LeafTypeAssumption.java new file mode 100644 index 000000000000..4b579587386d --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/hierarchy/LeafTypeAssumption.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.truffle.espresso.analysis.hierarchy; + +import com.oracle.truffle.api.Assumption; + +/** + * A wrapper around {@link Assumption}. Ensures that class hierarchy assumptions are managed + * exclusively by {@link ClassHierarchyOracle}. + */ +public interface LeafTypeAssumption { + Assumption getAssumption(); +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/hierarchy/NoOpClassHierarchyOracle.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/hierarchy/NoOpClassHierarchyOracle.java new file mode 100644 index 000000000000..8ff1fe2bbb77 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/hierarchy/NoOpClassHierarchyOracle.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.truffle.espresso.analysis.hierarchy; + +import com.oracle.truffle.api.Assumption; +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.utilities.AlwaysValidAssumption; +import com.oracle.truffle.api.utilities.NeverValidAssumption; +import com.oracle.truffle.espresso.impl.ObjectKlass; + +/** + * An implementation of {@link ClassHierarchyOracle} which simply checks {@code final} modifier of a + * class. + */ +public class NoOpClassHierarchyOracle implements ClassHierarchyOracle { + protected static class LeafTypeAssumptionImpl implements LeafTypeAssumption { + private final Assumption underlying; + + // Used only to create never valid and always valid instances + private LeafTypeAssumptionImpl(Assumption underlyingAssumption) { + underlying = underlyingAssumption; + } + + private LeafTypeAssumptionImpl(String assumptionName) { + underlying = Truffle.getRuntime().createAssumption(assumptionName); + } + + LeafTypeAssumptionImpl(ObjectKlass klass) { + this(klass.getNameAsString() + " is a leaf type"); + } + + @Override + public Assumption getAssumption() { + return underlying; + } + } + + protected static final LeafTypeAssumptionAccessor assumptionAccessor = new LeafTypeAssumptionAccessor(); + + protected static final LeafTypeAssumption FinalIsAlwaysLeaf = new LeafTypeAssumptionImpl(AlwaysValidAssumption.INSTANCE); + protected static final LeafTypeAssumption NotLeaf = new LeafTypeAssumptionImpl(NeverValidAssumption.INSTANCE); + + @Override + public LeafTypeAssumption createAssumptionForNewKlass(ObjectKlass newKlass) { + if (newKlass.isFinalFlagSet()) { + return FinalIsAlwaysLeaf; + } + return NotLeaf; + } + + @Override + public LeafTypeAssumption isLeafClass(ObjectKlass klass) { + return klass.getLeafTypeAssumption(assumptionAccessor); + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java index bd5065d04d3e..32f295559606 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java @@ -503,11 +503,9 @@ public static void ensureInitialized() { // Thread public static final Symbol interrupted = StaticSymbols.putName("interrupted"); public static final Symbol interrupt = StaticSymbols.putName("interrupt"); - public static final Symbol HIDDEN_DEATH = StaticSymbols.putName("0HIDDEN_DEATH"); - public static final Symbol HIDDEN_DEATH_THROWABLE = StaticSymbols.putName("0HIDDEN_DEATH_THROWABLE"); + public static final Symbol HIDDEN_DEPRECATION_SUPPORT = StaticSymbols.putName("0HIDDEN_DEPRECATION_SUPPORT"); public static final Symbol HIDDEN_HOST_THREAD = StaticSymbols.putName("0HIDDEN_HOST_THREAD"); public static final Symbol HIDDEN_INTERRUPTED = StaticSymbols.putName("0HIDDEN_INTERRUPTED"); - public static final Symbol HIDDEN_SUSPEND_LOCK = StaticSymbols.putName("0HIDDEN_SUSPEND_LOCK"); public static final Symbol HIDDEN_THREAD_BLOCKED_OBJECT = StaticSymbols.putName("0HIDDEN_THREAD_BLOCKED_OBJECT"); public static final Symbol HIDDEN_THREAD_BLOCKED_COUNT = StaticSymbols.putName("0HIDDEN_THREAD_BLOCKED_COUNT"); public static final Symbol HIDDEN_THREAD_WAITED_COUNT = StaticSymbols.putName("0HIDDEN_THREAD_WAITED_COUNT"); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistries.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistries.java index 8ccc73a41e62..85b70512fd78 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistries.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistries.java @@ -38,6 +38,7 @@ import com.oracle.truffle.espresso.descriptors.Symbol; import com.oracle.truffle.espresso.descriptors.Symbol.Type; import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.jdwp.api.ModuleRef; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.redefinition.DefineKlassListener; import com.oracle.truffle.espresso.runtime.EspressoContext; @@ -194,6 +195,20 @@ public Klass[] getAllLoadedClasses() { return list.toArray(Klass.EMPTY_ARRAY); } + public ModuleRef[] getAllModuleRefs() { + ArrayList list = new ArrayList<>(); + // add modules from boot registry + list.addAll(bootClassRegistry.modules().values()); + + // add modules from all other registries + synchronized (weakClassLoaderSet) { + for (StaticObject classLoader : weakClassLoaderSet) { + list.addAll(getClassRegistry(classLoader).modules().values()); + } + } + return list.toArray(ModuleRef.EMPTY_ARRAY); + } + /** * Do not call directly. Use * {@link com.oracle.truffle.espresso.meta.Meta#loadKlassOrFail(Symbol, StaticObject, StaticObject)} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ContextAccess.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ContextAccess.java index c98a05eb2ed5..1c278f219b5e 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ContextAccess.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ContextAccess.java @@ -23,15 +23,16 @@ package com.oracle.truffle.espresso.impl; import com.oracle.truffle.espresso.EspressoLanguage; -import com.oracle.truffle.espresso.ffi.NativeAccess; import com.oracle.truffle.espresso.descriptors.Names; import com.oracle.truffle.espresso.descriptors.Signatures; import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.ffi.NativeAccess; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.JavaVersion; import com.oracle.truffle.espresso.runtime.StringTable; import com.oracle.truffle.espresso.substitutions.Substitutions; +import com.oracle.truffle.espresso.threads.ThreadsAccess; import com.oracle.truffle.espresso.vm.InterpreterToVM; import com.oracle.truffle.espresso.vm.VM; @@ -62,6 +63,10 @@ default VM getVM() { return getContext().getVM(); } + default ThreadsAccess getThreadAccess() { + return getContext().getThreadAccess(); + } + default InterpreterToVM getInterpreterToVM() { return getContext().getInterpreterToVM(); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/EntryTable.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/EntryTable.java index b644d99f0c98..33c58d17fe3f 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/EntryTable.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/EntryTable.java @@ -23,6 +23,8 @@ package com.oracle.truffle.espresso.impl; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Objects; import java.util.concurrent.locks.Lock; @@ -42,6 +44,13 @@ protected EntryTable(ReadWriteLock lock) { this.writeBlock = new BlockLock(lock.writeLock()); } + @SuppressWarnings("try") + public Collection values() { + try (BlockLock block = read()) { + return Collections.unmodifiableCollection(entries.values()); + } + } + public static final class BlockLock implements AutoCloseable { private final Lock lock; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/InterfaceTables.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/InterfaceTables.java index b31c19e8e121..706a6fb725c7 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/InterfaceTables.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/InterfaceTables.java @@ -197,6 +197,7 @@ public static CreationResult create(ObjectKlass superKlass, ObjectKlass[] superI * @return the final itable */ public static Method[][] fixTables(Method[] vtable, Method[] mirandas, Method[] declaredMethods, Entry[][] tables, ObjectKlass[] iklassTable) { + assert tables.length == iklassTable.length; ArrayList tmpTables = new ArrayList<>(); // Second step @@ -205,12 +206,54 @@ public static Method[][] fixTables(Method[] vtable, Method[] mirandas, Method[] fixVTable(tables[i], vtable, mirandas, declaredMethods, iklassTable[i].getInterfaceMethodsTable()); } // Third step - for (Entry[] entries : tables) { - tmpTables.add(getITable(entries, vtable, mirandas, declaredMethods)); + for (int tableIndex = 0; tableIndex < tables.length; tableIndex++) { + Entry[] entries = tables[tableIndex]; + Method[] itable = getITable(entries, vtable, mirandas, declaredMethods); + tmpTables.add(itable); + + // Update leaf assumptions for super interfaces + ObjectKlass currInterface = iklassTable[tableIndex]; + updateLeafAssumptions(itable, currInterface); + } return tmpTables.toArray(EMPTY_METHOD_DUAL_ARRAY); } + /** + * Note: Leaf assumptions are not invalidated on creation of an interface. This means that in + * the following example: + * + *

    +     * interface A {
    +     *     default void m() {
    +     *     }
    +     * }
    +     * 
    +     * interface B extends A {
    +     *     default void m() {
    +     *     }
    +     * }
    +     * 
    + * + * Unless a concrete class that implements B is loaded, the leaf assumption for A.m() will not + * be invalidated. + */ + private static void updateLeafAssumptions(Method[] itable, ObjectKlass currInterface) { + for (int methodIndex = 0; methodIndex < itable.length; methodIndex++) { + Method m = itable[methodIndex]; + // This class' itable entry for this method is not the interface's declared method. + if (m.getDeclaringKlass() != currInterface) { + Method intfMethod = currInterface.getInterfaceMethodsTable()[methodIndex]; + // sanity checks + assert intfMethod.getDeclaringKlass() == currInterface; + assert m.canOverride(intfMethod) && m.getName() == intfMethod.getName() && m.getRawSignature() == intfMethod.getRawSignature(); + if (intfMethod.leafAssumption()) { + intfMethod.invalidateLeaf(); + } + } + } + } + // Actual implementations private CreationResult create() { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java index ccb341aa9b16..6e092ea5bd3a 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java @@ -29,9 +29,10 @@ import java.util.Comparator; import java.util.function.IntFunction; -import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.espresso.jdwp.api.ModuleRef; import org.graalvm.collections.EconomicSet; +import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -742,7 +743,7 @@ public final boolean isPrimitive() { * The setting of the final bit for types is a bit confusing since arrays are marked as final. * This method provides a semantically equivalent test that appropriate for types. */ - public boolean isLeaf() { + public boolean hasNoSubtypes() { return getElementalType().isFinalFlagSet(); } @@ -1564,5 +1565,10 @@ public String getSourceDebugExtension() { return null; } + @Override + public final ModuleRef getModule() { + return module(); + } + // endregion jdwp-specific } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlassFieldLayout.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlassFieldLayout.java index 7b296f56ce86..f485582cdb55 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlassFieldLayout.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlassFieldLayout.java @@ -248,9 +248,7 @@ private static HiddenField[] getHiddenFieldsFull(Symbol holder) { return new HiddenField[]{ new HiddenField(Name.HIDDEN_INTERRUPTED, Type._boolean, VersionRange.lower(13)), new HiddenField(Name.HIDDEN_HOST_THREAD), - new HiddenField(Name.HIDDEN_DEATH), - new HiddenField(Name.HIDDEN_DEATH_THROWABLE), - new HiddenField(Name.HIDDEN_SUSPEND_LOCK), + new HiddenField(Name.HIDDEN_DEPRECATION_SUPPORT), // Only used for j.l.management bookkeeping. new HiddenField(Name.HIDDEN_THREAD_BLOCKED_OBJECT), diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java index b6b86f7830cc..ec622b74b630 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java @@ -263,13 +263,8 @@ private Method(Method method, CodeAttribute split) { initRefKind(); this.proxy = null; - if (getDeclaringKlass().isInterface() || isAbstract()) { - /* - * TODO(peterssen): GR-33781 Leaf method assumption cannot be trusted for default - * methods. - * - * Also disabled for abstract methods to reduce footprint. - */ + if (isAbstract()) { + // Disabled for abstract methods to reduce footprint. this.isLeaf = NeverValidAssumption.INSTANCE; } else if (isStatic() || isPrivate() || isFinalFlagSet() || getDeclaringKlass().isFinalFlagSet()) { // Nothing to assume, spare an assumption. @@ -460,7 +455,7 @@ private CallTarget lookupLibJavaCallTarget() { // Look in libjava TruffleObject nativeMethod = lookupAndBind(getVM().getJavaLibrary(), mangledName); if (nativeMethod != null) { - return Truffle.getRuntime().createCallTarget(EspressoRootNode.create(null, new NativeMethodNode(nativeMethod, getMethodVersion()))); + return EspressoRootNode.create(null, new NativeMethodNode(nativeMethod, getMethodVersion())).getCallTarget(); } } } @@ -473,7 +468,7 @@ private CallTarget lookupAgents() { String mangledName = Mangle.mangleMethod(this, withSignature); TruffleObject nativeMethod = getContext().bindToAgent(this, mangledName); if (nativeMethod != null) { - return Truffle.getRuntime().createCallTarget(EspressoRootNode.create(null, new NativeMethodNode(nativeMethod, getMethodVersion()))); + return EspressoRootNode.create(null, new NativeMethodNode(nativeMethod, getMethodVersion())).getCallTarget(); } } return null; @@ -499,7 +494,7 @@ private CallTarget lookupJniCallTarget(Method findNative, boolean fullSignature) } TruffleObject symbol = getVM().getFunction(handle); TruffleObject nativeMethod = bind(symbol); - return Truffle.getRuntime().createCallTarget(EspressoRootNode.create(null, new NativeMethodNode(nativeMethod, this.getMethodVersion()))); + return EspressoRootNode.create(null, new NativeMethodNode(nativeMethod, this.getMethodVersion())).getCallTarget(); } public boolean isConstructor() { @@ -975,7 +970,7 @@ public Method forceSplit() { Method result = new Method(this, getCodeAttribute()); FrameDescriptor frameDescriptor = new FrameDescriptor(); EspressoRootNode root = EspressoRootNode.create(frameDescriptor, new BytecodeNode(result.getMethodVersion(), frameDescriptor)); - result.getMethodVersion().callTarget = Truffle.getRuntime().createCallTarget(root); + result.getMethodVersion().callTarget = root.getCallTarget(); return result; } @@ -1362,7 +1357,7 @@ private CallTarget getCallTarget(boolean initKlass) { */ EspressoRootNode redirectedMethod = getSubstitutions().get(getMethod()); if (redirectedMethod != null) { - callTarget = Truffle.getRuntime().createCallTarget(redirectedMethod); + callTarget = redirectedMethod.getCallTarget(); return callTarget; } @@ -1416,7 +1411,7 @@ private CallTarget findCallTarget() { } FrameDescriptor frameDescriptor = new FrameDescriptor(); EspressoRootNode rootNode = EspressoRootNode.create(frameDescriptor, new BytecodeNode(this, frameDescriptor)); - target = Truffle.getRuntime().createCallTarget(rootNode); + target = rootNode.getCallTarget(); } return target; } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ModuleTable.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ModuleTable.java index eb92346df63d..6afb0e33dbf2 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ModuleTable.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ModuleTable.java @@ -28,6 +28,7 @@ import com.oracle.truffle.espresso.descriptors.Symbol; import com.oracle.truffle.espresso.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.jdwp.api.ModuleRef; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.StaticObject; @@ -52,7 +53,7 @@ public ModuleEntry createAndAddEntry(Symbol name, ClassRegistry registry, return moduleEntry; } - public static class ModuleEntry extends EntryTable.NamedEntry { + public static class ModuleEntry extends EntryTable.NamedEntry implements ModuleRef { // TODO: module versions. ModuleEntry(Symbol name, ClassRegistry data) { @@ -60,6 +61,19 @@ public static class ModuleEntry extends EntryTable.NamedEntry { this.registry = data; } + public String jdwpName() { + if (name == null) { + // JDWP expects the unnamed module to return empty string + return ""; + } else { + return name.toString(); + } + } + + public Object classLoader() { + return registry.getClassLoader(); + } + public static ModuleEntry createUnnamedModuleEntry(StaticObject module, ClassRegistry registry) { ModuleEntry result = new ModuleEntry(null, registry); result.setCanReadAllUnnamed(); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java index 4fbc1d1c4d23..d7b0af6a8321 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java @@ -36,6 +36,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.logging.Level; @@ -46,6 +47,9 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.nodes.ExplodeLoop; +import com.oracle.truffle.espresso.analysis.hierarchy.ClassHierarchyOracle.LeafTypeAssumptionAccessor; +import com.oracle.truffle.espresso.analysis.hierarchy.LeafTypeAssumption; +import com.oracle.truffle.espresso.analysis.hierarchy.ClassHierarchyOracle; import com.oracle.truffle.espresso.classfile.ConstantPool; import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; import com.oracle.truffle.espresso.classfile.attributes.ConstantValueAttribute; @@ -141,6 +145,8 @@ public final class ObjectKlass extends Klass { private final StaticObject definingClassLoader; + private final LeafTypeAssumption leafTypeAssumption; + public Attribute getAttribute(Symbol attrName) { return getLinkedKlass().getAttribute(attrName); } @@ -229,6 +235,7 @@ public ObjectKlass(EspressoContext context, LinkedKlass linkedKlass, ObjectKlass initSelfReferenceInPool(); } + this.leafTypeAssumption = getContext().getClassHierarchyOracle().createAssumptionForNewKlass(this); this.initState = LOADED; assert verifyTables(); } @@ -343,12 +350,6 @@ private void actualInit() { } initState = INITIALIZING; try { - if (getContext().isMainThreadCreated()) { - if (getContext().shouldReportVMEvents()) { - prepareThread = getContext().getGuestThreadFromHost(Thread.currentThread()); - getContext().reportClassPrepared(this, prepareThread); - } - } if (!isInterface()) { /* * Next, if C is a class rather than an interface, then let SC be its superclass @@ -460,6 +461,12 @@ private void prepare() { } } initState = PREPARED; + if (getContext().isMainThreadCreated()) { + if (getContext().shouldReportVMEvents()) { + prepareThread = getContext().getGuestThreadFromHost(Thread.currentThread()); + getContext().reportClassPrepared(this, prepareThread); + } + } } } } @@ -1399,6 +1406,19 @@ public void removeByRedefinition() { } } + /** + * This getter must only be used by {@link ClassHierarchyOracle}, which is ensured by + * {@code assumptionAccessor}. The assumption is stored in ObjectKlass for easy mapping between + * classes and corresponding assumptions. + * + * @see ClassHierarchyOracle#isLeafClass(ObjectKlass) + * @return the assumption, indicating if this class is a leaf in class hierarchy. + */ + public LeafTypeAssumption getLeafTypeAssumption(LeafTypeAssumptionAccessor assumptionAccessor) { + Objects.requireNonNull(assumptionAccessor); + return leafTypeAssumption; + } + public final class KlassVersion { final Assumption assumption; final RuntimeConstantPool pool; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/PrimitiveKlass.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/PrimitiveKlass.java index d9f129e43f3e..0760ccf94b86 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/PrimitiveKlass.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/PrimitiveKlass.java @@ -25,6 +25,7 @@ import java.lang.reflect.Modifier; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.espresso.classfile.ConstantPool; import com.oracle.truffle.espresso.descriptors.Symbol; import com.oracle.truffle.espresso.descriptors.Symbol.Name; @@ -36,6 +37,7 @@ import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.StaticObject; import com.oracle.truffle.espresso.substitutions.JavaType; +import com.oracle.truffle.espresso.vm.InterpreterToVM; /** * Implementation of {@link Klass} for primitive types. Primitive classes don't have a .class @@ -147,4 +149,9 @@ public String toString() { public int getClassModifiers() { return getModifiers(); } + + @CompilerDirectives.TruffleBoundary + public StaticObject allocatePrimitiveArray(int length) { + return InterpreterToVM.allocatePrimitiveArray((byte) getPrimitiveJavaKind().getBasicType(), length, getMeta()); + } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java index 334df63f54bd..325a709d3d72 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java @@ -359,9 +359,7 @@ public Meta(EspressoContext context) { .field(higher(14), Name.interrupted, Type._boolean) // .maybeHiddenfield(java_lang_Thread); HIDDEN_HOST_THREAD = java_lang_Thread.requireHiddenField(Name.HIDDEN_HOST_THREAD); - HIDDEN_DEATH = java_lang_Thread.requireHiddenField(Name.HIDDEN_DEATH); - HIDDEN_DEATH_THROWABLE = java_lang_Thread.requireHiddenField(Name.HIDDEN_DEATH_THROWABLE); - HIDDEN_SUSPEND_LOCK = java_lang_Thread.requireHiddenField(Name.HIDDEN_SUSPEND_LOCK); + HIDDEN_DEPRECATION_SUPPORT = java_lang_Thread.requireHiddenField(Name.HIDDEN_DEPRECATION_SUPPORT); if (context.EnableManagement) { HIDDEN_THREAD_BLOCKED_OBJECT = java_lang_Thread.requireHiddenField(Name.HIDDEN_THREAD_BLOCKED_OBJECT); @@ -1171,9 +1169,7 @@ private DiffVersionLoadHelper diff() { public final Method java_lang_Thread_stop; public final Field HIDDEN_HOST_THREAD; public final Field HIDDEN_INTERRUPTED; - public final Field HIDDEN_DEATH; - public final Field HIDDEN_DEATH_THROWABLE; - public final Field HIDDEN_SUSPEND_LOCK; + public final Field HIDDEN_DEPRECATION_SUPPORT; public final Field HIDDEN_THREAD_BLOCKED_OBJECT; public final Field HIDDEN_THREAD_BLOCKED_COUNT; public final Field HIDDEN_THREAD_WAITED_COUNT; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java index 6dd3394b3748..dfc308c92617 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java @@ -257,11 +257,11 @@ import com.oracle.truffle.api.instrumentation.StandardTags.StatementTag; import com.oracle.truffle.api.instrumentation.Tag; import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.nodes.BytecodeOSRNode; import com.oracle.truffle.api.nodes.ControlFlowException; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.BytecodeOSRNode; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.espresso.analysis.liveness.LivenessAnalysis; @@ -339,7 +339,6 @@ import com.oracle.truffle.espresso.runtime.EspressoExitException; import com.oracle.truffle.espresso.runtime.ReturnAddress; import com.oracle.truffle.espresso.runtime.StaticObject; -import com.oracle.truffle.espresso.substitutions.Target_java_lang_Thread; import com.oracle.truffle.espresso.vm.InterpreterToVM; /** @@ -1783,7 +1782,7 @@ private int beforeJumpChecks(long[] primitives, Object[] refs, int curBCI, int t CompilerAsserts.partialEvaluationConstant(targetBCI); int nextStatementIndex = (instrument == null) ? 0 : instrument.getStatementIndexAfterJump(statementIndex, curBCI, targetBCI); if (targetBCI <= curBCI) { - checkStopping(); + checkDeprecation(); if (++loopCount[0] >= REPORT_LOOP_STRIDE) { LoopNode.reportLoopCount(this, REPORT_LOOP_STRIDE); loopCount[0] = 0; @@ -1814,9 +1813,9 @@ private int beforeJumpChecks(long[] primitives, Object[] refs, int curBCI, int t return nextStatementIndex; } - private void checkStopping() { + private void checkDeprecation() { if (getContext().shouldCheckDeprecationStatus()) { - Target_java_lang_Thread.checkDeprecatedState(getMeta(), getContext().getCurrentThread()); + getContext().getThreadAccess().checkDeprecation(); } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InstanceOf.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InstanceOf.java index c618635b0c69..7cda041fff6f 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InstanceOf.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InstanceOf.java @@ -22,6 +22,7 @@ */ package com.oracle.truffle.espresso.nodes.bytecodes; +import com.oracle.truffle.api.Assumption; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.GenerateUncached; @@ -29,6 +30,7 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.profiles.BranchProfile; +import com.oracle.truffle.espresso.analysis.hierarchy.LeafTypeAssumption; import com.oracle.truffle.espresso.impl.ArrayKlass; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.impl.ObjectKlass; @@ -226,7 +228,21 @@ abstract static class ConstantClass extends InstanceOf { this.superType = superType; } - @Specialization + protected LeafTypeAssumption getLeafAssumption() { + return EspressoContext.get(this).getClassHierarchyOracle().isLeafClass(superType); + } + + /** + * If {@code superType} is a leaf type, {@code maybeSubtype} is a subtype of + * {@code superType} iff it is equal to {@code superType}. + */ + @Specialization(assumptions = "superTypeIsLeaf") + public boolean doLeaf(ObjectKlass maybeSubtype, + @SuppressWarnings("unused") @Cached("getLeafAssumption().getAssumption()") Assumption superTypeIsLeaf) { + return superType == maybeSubtype; + } + + @Specialization(replaces = "doLeaf") public boolean doObjectKlass(ObjectKlass maybeSubtype) { return superType == maybeSubtype || superType.checkOrdinaryClassSubclassing(maybeSubtype); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InvokeInterface.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InvokeInterface.java index 4c1129951d7e..e01a1a11ad72 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InvokeInterface.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InvokeInterface.java @@ -76,7 +76,6 @@ static StaticObject getReceiver(Object[] args) { return (StaticObject) args[0]; } - @ReportPolymorphism @ImportStatic(InvokeInterface.class) @NodeInfo(shortName = "INVOKEINTERFACE !nullcheck") public abstract static class WithoutNullCheck extends Node { @@ -125,7 +124,7 @@ static Method.MethodVersion methodLookup(Method resolutionSeed, StaticObject rec * Accept a slow path once the method has been removed put method behind a boundary to * avoid a deopt loop */ - return ClassRedefinition.handleRemovedMethod(resolutionSeed, receiver.getKlass(), receiver).getMethodVersion(); + return ClassRedefinition.handleRemovedMethod(resolutionSeed, receiver.getKlass()).getMethodVersion(); } int iTableIndex = resolutionSeed.getITableIndex(); @@ -156,7 +155,6 @@ Object executeWithNullCheck(Method resolutionSeed, Object[] args, } @GenerateUncached - @ReportPolymorphism @NodeInfo(shortName = "INVOKEINTERFACE dynamic !nullcheck") public abstract static class WithoutNullCheck extends Node { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InvokeSpecial.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InvokeSpecial.java index 212e29c84733..a26bb8453ae6 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InvokeSpecial.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InvokeSpecial.java @@ -74,12 +74,11 @@ static Method.MethodVersion methodLookup(Method method, StaticObject receiver) { * Accept a slow path once the method has been removed put method behind a boundary to * avoid a deopt loop. */ - return ClassRedefinition.handleRemovedMethod(method, receiver.getKlass(), receiver).getMethodVersion(); + return ClassRedefinition.handleRemovedMethod(method, receiver.getKlass()).getMethodVersion(); } return method.getMethodVersion(); } - @ReportPolymorphism @ImportStatic(InvokeSpecial.class) @NodeInfo(shortName = "INVOKESPECIAL !nullcheck") public abstract static class WithoutNullCheck extends Node { @@ -137,7 +136,6 @@ Object executeWithNullCheck(Method method, Object[] args, } @GenerateUncached - @ReportPolymorphism @NodeInfo(shortName = "INVOKESPECIAL dynamic !nullcheck") public abstract static class WithoutNullCheck extends Node { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InvokeStatic.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InvokeStatic.java index 7ff6fa79257f..91ccfa8b0a0a 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InvokeStatic.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InvokeStatic.java @@ -59,9 +59,9 @@ public abstract class InvokeStatic extends Node { @Specialization Object callWithClassInitCheck(Object[] args, @Cached InitCheck initCheck, - @Cached("create(staticMethod)") WithoutClassInitCheck invokeVirtual) { + @Cached("create(staticMethod)") WithoutClassInitCheck invokeStatic) { initCheck.execute(staticMethod.getDeclaringKlass()); - return invokeVirtual.execute(args); + return invokeStatic.execute(args); } @ImportStatic(InvokeStatic.class) @@ -104,7 +104,7 @@ static Method.MethodVersion methodLookup(Method staticMethod) { * Accept a slow path once the method has been removed put method behind a boundary to * avoid a deopt loop. */ - return ClassRedefinition.handleRemovedMethod(staticMethod, staticMethod.getDeclaringKlass(), null).getMethodVersion(); + return ClassRedefinition.handleRemovedMethod(staticMethod, staticMethod.getDeclaringKlass()).getMethodVersion(); } return staticMethod.getMethodVersion(); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InvokeVirtual.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InvokeVirtual.java index 508d74fea763..01f0d7b552c4 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InvokeVirtual.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/bytecodes/InvokeVirtual.java @@ -79,7 +79,6 @@ static StaticObject getReceiver(Object[] args) { return (StaticObject) args[0]; } - @ReportPolymorphism @ImportStatic(InvokeVirtual.class) @NodeInfo(shortName = "INVOKEVIRTUAL !nullcheck") public abstract static class WithoutNullCheck extends Node { @@ -162,7 +161,7 @@ static Method.MethodVersion methodLookup(Method resolutionSeed, StaticObject rec * Accept a slow path once the method has been removed put method behind a boundary to * avoid a deopt loop. */ - return ClassRedefinition.handleRemovedMethod(resolutionSeed, receiver.getKlass(), receiver).getMethodVersion(); + return ClassRedefinition.handleRemovedMethod(resolutionSeed, receiver.getKlass()).getMethodVersion(); } /* * Surprisingly, INVOKEVIRTUAL can try to invoke interface methods, even non-default ones. @@ -201,7 +200,6 @@ Object executeWithNullCheck(Method resolutionSeed, Object[] args, } @GenerateUncached - @ReportPolymorphism @NodeInfo(shortName = "INVOKEVIRTUAL dynamic !nullcheck") public abstract static class WithoutNullCheck extends Node { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/InvokeEspressoNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/InvokeEspressoNode.java index 3cd008142326..8d7f0bbb86a7 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/InvokeEspressoNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/InvokeEspressoNode.java @@ -47,7 +47,7 @@ public abstract class InvokeEspressoNode extends Node { public final Object execute(Method method, Object receiver, Object[] arguments) throws ArityException, UnsupportedTypeException { Method resolutionSeed = method; if (resolutionSeed.isRemovedByRedefition()) { - resolutionSeed = ClassRedefinition.handleRemovedMethod(method, method.isStatic() ? method.getDeclaringKlass() : ((StaticObject) receiver).getKlass(), (StaticObject) receiver); + resolutionSeed = ClassRedefinition.handleRemovedMethod(method, method.isStatic() ? method.getDeclaringKlass() : ((StaticObject) receiver).getKlass()); } Object result = executeMethod(resolutionSeed.getMethodVersion(), receiver, arguments); /* diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MHLinkToNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MHLinkToNode.java index 84cf7c747181..a8b2e3afc941 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MHLinkToNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MHLinkToNode.java @@ -83,7 +83,7 @@ public Object call(Object[] args) { // method might have been redefined or removed by redefinition if (resolutionSeed.isRemovedByRedefition()) { Klass receiverKlass = hasReceiver ? ((StaticObject) basicArgs[0]).getKlass() : resolutionSeed.getDeclaringKlass(); - resolutionSeed = ClassRedefinition.handleRemovedMethod(resolutionSeed, receiverKlass, hasReceiver ? ((StaticObject) basicArgs[0]) : null); + resolutionSeed = ClassRedefinition.handleRemovedMethod(resolutionSeed, receiverKlass); } Method target = linker.linkTo(resolutionSeed, args); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/overlay/ReferenceSupport.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/overlay/ReferenceSupport.java new file mode 100644 index 000000000000..009da4415068 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/overlay/ReferenceSupport.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.truffle.espresso.overlay; + +import java.lang.ref.PhantomReference; +import java.lang.ref.Reference; + +import com.oracle.truffle.espresso.runtime.StaticObject; + +public class ReferenceSupport { + @SuppressWarnings("unused") + public static boolean phantomReferenceRefersTo(Reference ref, StaticObject object) { + assert (ref instanceof PhantomReference); + return false; + } + + public static boolean referenceRefersTo(Reference ref, StaticObject object) { + assert !(ref instanceof PhantomReference); + StaticObject value = ref.get(); + value = value == null ? StaticObject.NULL : value; + return value == object; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ClassRedefinition.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ClassRedefinition.java index e782be2555ab..02866d682172 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ClassRedefinition.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ClassRedefinition.java @@ -594,12 +594,15 @@ private void doRedefineClass(ChangePacket packet, List refreshSubCl } } + /** + * @param accessingKlass the receiver's klass when the method is not static, resolutionSeed's + * declaring klass otherwise + */ @TruffleBoundary - public static Method handleRemovedMethod(Method resolutionSeed, Klass accessingKlass, StaticObject receiver) { + public static Method handleRemovedMethod(Method resolutionSeed, Klass accessingKlass) { // wait for potential ongoing redefinition to complete check(); - Klass lookupKlass = receiver != null ? receiver.getKlass() : resolutionSeed.getDeclaringKlass(); - Method replacementMethod = lookupKlass.lookupMethod(resolutionSeed.getName(), resolutionSeed.getRawSignature(), accessingKlass); + Method replacementMethod = accessingKlass.lookupMethod(resolutionSeed.getName(), resolutionSeed.getRawSignature(), accessingKlass); Meta meta = resolutionSeed.getMeta(); if (replacementMethod == null) { throw meta.throwExceptionWithMessage(meta.java_lang_NoSuchMethodError, diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoContext.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoContext.java index 70771e74d2e5..45c356cbc100 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoContext.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoContext.java @@ -44,6 +44,8 @@ import java.util.logging.Level; import java.util.stream.Collectors; +import com.oracle.truffle.espresso.analysis.hierarchy.DefaultClassHierarchyOracle; +import com.oracle.truffle.espresso.analysis.hierarchy.NoOpClassHierarchyOracle; import org.graalvm.options.OptionMap; import org.graalvm.polyglot.Engine; @@ -66,6 +68,7 @@ import com.oracle.truffle.espresso.EspressoLanguage; import com.oracle.truffle.espresso.EspressoOptions; import com.oracle.truffle.espresso.FinalizationSupport; +import com.oracle.truffle.espresso.analysis.hierarchy.ClassHierarchyOracle; import com.oracle.truffle.espresso.descriptors.Names; import com.oracle.truffle.espresso.descriptors.Signatures; import com.oracle.truffle.espresso.descriptors.Symbol; @@ -89,7 +92,8 @@ import com.oracle.truffle.espresso.perf.TimerCollection; import com.oracle.truffle.espresso.redefinition.plugins.api.InternalRedefinitionPlugin; import com.oracle.truffle.espresso.substitutions.Substitutions; -import com.oracle.truffle.espresso.substitutions.Target_java_lang_Thread; +import com.oracle.truffle.espresso.threads.EspressoThreadRegistry; +import com.oracle.truffle.espresso.threads.ThreadsAccess; import com.oracle.truffle.espresso.vm.InterpreterToVM; import com.oracle.truffle.espresso.vm.UnsafeAccess; import com.oracle.truffle.espresso.vm.VM; @@ -129,10 +133,12 @@ public final class EspressoContext { private final ClassRegistries registries; private final Substitutions substitutions; private final MethodHandleIntrinsics methodHandleIntrinsics; + private final ClassHierarchyOracle classHierarchyOracle; // endregion Runtime // region Helpers - private final EspressoThreadManager threadManager; + private final EspressoThreadRegistry threadRegistry; + @CompilationFinal private ThreadsAccess threads; private final EspressoShutdownHandler shutdownManager; private final EspressoReferenceDrainer referenceDrainer; // endregion Helpers @@ -168,6 +174,7 @@ public final class EspressoContext { public final boolean InlineMethodHandle; public final boolean SplitMethodHandles; public final boolean livenessAnalysis; + public final boolean EnableClassHierarchyAnalysis; // Behavior control public final boolean EnableManagement; @@ -247,12 +254,12 @@ public EspressoContext(TruffleLanguage.Env env, EspressoLanguage language) { this.substitutions = new Substitutions(this); this.methodHandleIntrinsics = new MethodHandleIntrinsics(this); - this.threadManager = new EspressoThreadManager(this); + this.threadRegistry = new EspressoThreadRegistry(this); this.referenceDrainer = new EspressoReferenceDrainer(this); boolean softExit = env.getOptions().get(EspressoOptions.SoftExit); this.ExitHost = env.getOptions().get(EspressoOptions.ExitHost); - this.shutdownManager = new EspressoShutdownHandler(this, threadManager, referenceDrainer, softExit); + this.shutdownManager = new EspressoShutdownHandler(this, threadRegistry, referenceDrainer, softExit); this.timers = TimerCollection.create(env.getOptions().get(EspressoOptions.EnableTimers)); this.allocationReporter = env.lookup(AllocationReporter.class); @@ -269,6 +276,7 @@ public EspressoContext(TruffleLanguage.Env env, EspressoLanguage language) { this.EnableSignals = env.getOptions().get(EspressoOptions.EnableSignals); this.SpecCompliancyMode = env.getOptions().get(EspressoOptions.SpecCompliancy); this.livenessAnalysis = env.getOptions().get(EspressoOptions.LivenessAnalysis); + this.EnableClassHierarchyAnalysis = env.getOptions().get(EspressoOptions.CHA); this.EnableManagement = env.getOptions().get(EspressoOptions.EnableManagement); this.EnableAgents = getEnv().getOptions().get(EspressoOptions.EnableAgents); this.TrivialMethodSize = getEnv().getOptions().get(EspressoOptions.TrivialMethodSize); @@ -293,6 +301,11 @@ public EspressoContext(TruffleLanguage.Env env, EspressoLanguage language) { this.vmArguments = buildVmArguments(); this.jdwpContext = new JDWPContextImpl(this); + if (this.EnableClassHierarchyAnalysis) { + this.classHierarchyOracle = new DefaultClassHierarchyOracle(); + } else { + this.classHierarchyOracle = new NoOpClassHierarchyOracle(); + } } private static Set knownSingleThreadedLanguages(TruffleLanguage.Env env) { @@ -477,6 +490,7 @@ private void spawnVM() { this.meta = new Meta(this); } this.metaInitialized = true; + this.threads = new ThreadsAccess(meta); this.interpreterToVM = new InterpreterToVM(this); @@ -499,7 +513,7 @@ private void spawnVM() { } // Create main thread as soon as Thread class is initialized. - threadManager.createMainThread(meta); + threadRegistry.createMainThread(meta); try (DebugCloseable knownClassInit = KNOWN_CLASS_INIT.scope(timers)) { initializeKnownClass(Type.java_lang_Object); @@ -775,15 +789,19 @@ public TruffleObject bindToAgent(Method method, String mangledName) { // region Thread management + public ThreadsAccess getThreadAccess() { + return threads; + } + /** * Creates a new guest thread from the host thread, and adds it to the main thread group. */ public StaticObject createThread(Thread hostThread) { - return threadManager.createGuestThreadFromHost(hostThread, meta, vm); + return threadRegistry.createGuestThreadFromHost(hostThread, meta, vm); } public StaticObject createThread(Thread hostThread, StaticObject group, String name) { - return threadManager.createGuestThreadFromHost(hostThread, meta, vm, name, group); + return threadRegistry.createGuestThreadFromHost(hostThread, meta, vm, name, group); } public void disposeThread(@SuppressWarnings("unused") Thread hostThread) { @@ -792,7 +810,7 @@ public void disposeThread(@SuppressWarnings("unused") Thread hostThread) { return; } if (hostThread != Thread.currentThread()) { - String guestName = Target_java_lang_Thread.getThreadName(meta, guestThread); + String guestName = threads.getThreadName(guestThread); getLogger().warning("unimplemented: disposeThread for non-current thread: " + hostThread + " / " + guestName); return; } @@ -802,47 +820,47 @@ public void disposeThread(@SuppressWarnings("unused") Thread hostThread) { } public StaticObject getGuestThreadFromHost(Thread host) { - return threadManager.getGuestThreadFromHost(host); + return threadRegistry.getGuestThreadFromHost(host); } public StaticObject getCurrentThread() { - return threadManager.getGuestThreadFromHost(Thread.currentThread()); + return threadRegistry.getGuestThreadFromHost(Thread.currentThread()); } /** * Returns the maximum number of alive (registered) threads at any point, since the VM started. */ public long getPeakThreadCount() { - return threadManager.peakThreadCount.get(); + return threadRegistry.peakThreadCount.get(); } /** * Returns the number of created threads since the VM started. */ public long getCreatedThreadCount() { - return threadManager.createdThreadCount.get(); + return threadRegistry.createdThreadCount.get(); } public StaticObject[] getActiveThreads() { - return threadManager.activeThreads(); + return threadRegistry.activeThreads(); } public void registerThread(Thread host, StaticObject self) { - threadManager.registerThread(host, self); + threadRegistry.registerThread(host, self); if (shouldReportVMEvents) { eventListener.threadStarted(self); } } public void unregisterThread(StaticObject self) { - threadManager.unregisterThread(self); + threadRegistry.unregisterThread(self); if (shouldReportVMEvents) { eventListener.threadDied(self); } } public void interruptThread(StaticObject guestThread) { - threadManager.interruptThread(guestThread); + threads.interruptThread(guestThread); } public void invalidateNoThreadStop(String message) { @@ -868,15 +886,15 @@ public boolean shouldCheckSuspend() { } public boolean isMainThreadCreated() { - return threadManager.isMainThreadCreated(); + return threadRegistry.isMainThreadCreated(); } public StaticObject getMainThread() { - return threadManager.getMainThread(); + return threadRegistry.getMainThread(); } public StaticObject getMainThreadGroup() { - return threadManager.getMainThreadGroup(); + return threadRegistry.getMainThreadGroup(); } // endregion Thread management @@ -1016,4 +1034,8 @@ public void rerunclinit(ObjectKlass oldKlass) { public static EspressoContext get(Node node) { return REFERENCE.get(node); } + + public ClassHierarchyOracle getClassHierarchyOracle() { + return classHierarchyOracle; + } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoReferenceDrainer.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoReferenceDrainer.java index cf862476da4f..c1dddc5bfdb0 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoReferenceDrainer.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoReferenceDrainer.java @@ -207,7 +207,7 @@ public void run() { } } } finally { - Target_java_lang_Thread.terminate(context.getCurrentThread(), meta); + context.getThreadAccess().terminate(context.getCurrentThread()); if (context.isClosing()) { // Ignore exceptions that arise during closing. return; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoShutdownHandler.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoShutdownHandler.java index c5974e0936a6..2a475e3c3d08 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoShutdownHandler.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoShutdownHandler.java @@ -26,15 +26,14 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.espresso.impl.ContextAccess; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.Meta; -import com.oracle.truffle.espresso.substitutions.Target_java_lang_Thread; +import com.oracle.truffle.espresso.threads.EspressoThreadRegistry; class EspressoShutdownHandler implements ContextAccess { // region context private final EspressoContext context; - private final EspressoThreadManager threadManager; + private final EspressoThreadRegistry threadManager; private final EspressoReferenceDrainer referenceDrainer; private final boolean softExit; @@ -46,7 +45,7 @@ public EspressoContext getContext() { // endregion context EspressoShutdownHandler(EspressoContext context, - EspressoThreadManager threadManager, + EspressoThreadRegistry threadManager, EspressoReferenceDrainer referenceDrainer, boolean softExit) { this.context = context; this.threadManager = threadManager; @@ -110,9 +109,8 @@ Object getShutdownSynchronizer() { @TruffleBoundary void doExit(int code) { getContext().getLogger().fine(() -> { - Meta meta = getMeta(); StaticObject currentThread = getContext().getCurrentThread(); - String guestName = Target_java_lang_Thread.getThreadName(meta, currentThread); + String guestName = getThreadAccess().getThreadName(currentThread); return "doExit(" + code + ") from " + guestName; }); if (!isClosing()) { @@ -197,7 +195,7 @@ private void waitForClose() throws EspressoExitException { private boolean hasActiveNonDaemon(Thread initiating) { for (StaticObject guest : threadManager.activeThreads()) { - Thread host = Target_java_lang_Thread.getHostFromGuestThread(guest); + Thread host = getThreadAccess().getHost(guest); if (host != initiating && !host.isDaemon()) { if (host.isAlive()) { return true; @@ -262,12 +260,12 @@ private void teardown(boolean killThreads) { */ private void teardownPhase1(Thread initiatingThread) { for (StaticObject guest : threadManager.activeThreads()) { - Thread t = Target_java_lang_Thread.getHostFromGuestThread(guest); + Thread t = getThreadAccess().getHost(guest); if (t.isAlive() && t != initiatingThread) { if (t.isDaemon()) { - Target_java_lang_Thread.killThread(guest); + context.getThreadAccess().stop(guest, null); } - threadManager.interruptThread(guest); + context.getThreadAccess().interruptThread(guest); } } } @@ -278,10 +276,10 @@ private void teardownPhase1(Thread initiatingThread) { */ private void teardownPhase2(Thread initiatingThread) { for (StaticObject guest : threadManager.activeThreads()) { - Thread t = Target_java_lang_Thread.getHostFromGuestThread(guest); + Thread t = getThreadAccess().getHost(guest); if (t.isAlive() && t != initiatingThread) { - Target_java_lang_Thread.killThread(guest); - threadManager.interruptThread(guest); + context.getThreadAccess().stop(guest, null); + context.getThreadAccess().interruptThread(guest); } } } @@ -293,15 +291,15 @@ private void teardownPhase2(Thread initiatingThread) { */ private void teardownPhase3(Thread initiatingThread) { for (StaticObject guest : threadManager.activeThreads()) { - Thread t = Target_java_lang_Thread.getHostFromGuestThread(guest); + Thread t = getThreadAccess().getHost(guest); if (t.isAlive() && t != initiatingThread) { /* * Currently, threads in native can not be killed in Espresso. This translates into * a polyglot-side java.lang.IllegalStateException: The language did not complete * all polyglot threads but should have. */ - Target_java_lang_Thread.forceKillThread(guest); - threadManager.interruptThread(guest); + context.getThreadAccess().kill(guest); + context.getThreadAccess().interruptThread(guest); } } } @@ -311,7 +309,7 @@ private void teardownPhase3(Thread initiatingThread) { */ private void teardownPhase4(Thread initiatingThread) { for (StaticObject guest : threadManager.activeThreads()) { - Thread t = Target_java_lang_Thread.getHostFromGuestThread(guest); + Thread t = getThreadAccess().getHost(guest); if (t.isAlive() && t != initiatingThread) { // TODO(garcia): Tell truffle to forget about this thread // Or @@ -334,7 +332,7 @@ private boolean waitSpin(Thread initiatingThread) { return false; } for (StaticObject guest : threadManager.activeThreads()) { - Thread t = Target_java_lang_Thread.getHostFromGuestThread(guest); + Thread t = getThreadAccess().getHost(guest); if (t != initiatingThread) { if (t.isAlive()) { continue spinLoop; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JDWPContextImpl.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JDWPContextImpl.java index 63721330524f..40a15b291a04 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JDWPContextImpl.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JDWPContextImpl.java @@ -54,6 +54,7 @@ import com.oracle.truffle.espresso.jdwp.api.JDWPSetup; import com.oracle.truffle.espresso.jdwp.api.KlassRef; import com.oracle.truffle.espresso.jdwp.api.MethodRef; +import com.oracle.truffle.espresso.jdwp.api.ModuleRef; import com.oracle.truffle.espresso.jdwp.api.MonitorStackInfo; import com.oracle.truffle.espresso.jdwp.api.RedefineInfo; import com.oracle.truffle.espresso.jdwp.api.TagConstants; @@ -74,7 +75,7 @@ import com.oracle.truffle.espresso.redefinition.RedefintionNotSupportedException; import com.oracle.truffle.espresso.redefinition.plugins.impl.RedefinitionPluginHandler; import com.oracle.truffle.espresso.runtime.dispatch.EspressoInterop; -import com.oracle.truffle.espresso.substitutions.Target_java_lang_Thread; +import com.oracle.truffle.espresso.threads.State; public final class JDWPContextImpl implements JDWPContext { @@ -128,7 +129,7 @@ public boolean isValidThread(Object thread, boolean checkTerminated) { if (context.getMeta().java_lang_Thread.isAssignableFrom(staticObject.getKlass())) { if (checkTerminated) { // check if thread has been terminated - return getThreadStatus(thread) != Target_java_lang_Thread.State.TERMINATED.value; + return getThreadStatus(thread) != State.TERMINATED.value; } return true; } @@ -251,7 +252,7 @@ public Object asGuestThread(Thread hostThread) { @Override public Thread asHostThread(Object thread) { - return Target_java_lang_Thread.getHostFromGuestThread((StaticObject) thread); + return context.getThreadAccess().getHost((StaticObject) thread); } @Override @@ -366,7 +367,7 @@ private static boolean isBoxedPrimitive(Class clazz) { @Override public String getThreadName(Object thread) { - return Target_java_lang_Thread.getThreadName(context.getMeta(), (StaticObject) thread); + return context.getThreadAccess().getThreadName((StaticObject) thread); } @Override @@ -542,7 +543,7 @@ public boolean isInstanceOf(Object object, KlassRef klass) { @Override public void stopThread(Object guestThread, Object guestThrowable) { - Target_java_lang_Thread.stop0((StaticObject) guestThread, (StaticObject) guestThrowable); + context.getThreadAccess().stop((StaticObject) guestThread, (StaticObject) guestThrowable); } @Override @@ -711,6 +712,21 @@ public Node getInstrumentableNode(RootNode rootNode) { return rootNode; } + @Override + public boolean isMemberOf(Object guestObject, KlassRef klass) { + if (guestObject instanceof StaticObject) { + StaticObject staticObject = (StaticObject) guestObject; + return klass.isAssignable(staticObject.getKlass()); + } else { + return false; + } + } + + @Override + public ModuleRef[] getAllModulesRefs() { + return context.getRegistries().getAllModuleRefs(); + } + public void rerunclinit(ObjectKlass oldKlass) { classInitializerActions.add(new ReloadingAction(oldKlass)); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/EspressoReference.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/EspressoReference.java index c081fc92a1ee..9c795c8652b1 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/EspressoReference.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/EspressoReference.java @@ -94,7 +94,7 @@ public StaticObject getGuestReference() { /** * Usable version of {@link PublicFinalReference} is injected early via - * {@link sun.misc.Unsafe#defineClass} on the the boot class loader. + * {@code sun.misc.Unsafe#defineClass} on the the boot class loader. */ final class EspressoFinalReference extends PublicFinalReference implements EspressoReference { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_com_oracle_truffle_espresso_polyglot_Interop.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_com_oracle_truffle_espresso_polyglot_Interop.java index d289fa3968d9..351bdfc34962 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_com_oracle_truffle_espresso_polyglot_Interop.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_com_oracle_truffle_espresso_polyglot_Interop.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -695,9 +695,11 @@ boolean doCached( /** * Returns exception exit status of the receiver. Throws {@code UnsupportedMessageException} * when the receiver is not an {@link InteropLibrary#isException(Object) exception} of the - * {@link ExceptionType#EXIT exit type}. A return value zero indicates that the execution of the - * application was successful, a non-zero value that it failed. The individual interpretation of - * non-zero values depends on the application. + * {@link ExceptionType#EXIT exit type}. See + *
    Context Exit + * for further information. A return value zero indicates that the execution of the application + * was successful, a non-zero value that it failed. The individual interpretation of non-zero + * values depends on the application. * * @see InteropLibrary#getExceptionExitStatus(Object) * @since 20.3 diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_Thread.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_Thread.java index a5586730767f..5fb155777a77 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_Thread.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_Thread.java @@ -33,12 +33,11 @@ import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.espresso.impl.Field; import com.oracle.truffle.espresso.impl.Klass; -import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.runtime.EspressoContext; -import com.oracle.truffle.espresso.runtime.EspressoException; -import com.oracle.truffle.espresso.runtime.EspressoExitException; import com.oracle.truffle.espresso.runtime.StaticObject; +import com.oracle.truffle.espresso.threads.State; +import com.oracle.truffle.espresso.threads.ThreadsAccess; // @formatter:off /** @@ -82,74 +81,6 @@ public static long getThreadCounter(StaticObject thread, Field hiddenField) { return atomicCounter.get(); } - public enum State { - NEW(0), - RUNNABLE(4), - BLOCKED(1024), - WAITING(16), - TIMED_WAITING(32), - TERMINATED(2); - - public final int value; - - State(int value) { - this.value = value; - } - - } - - public static void fromRunnable(StaticObject self, Meta meta, State state) { - assert meta.java_lang_Thread_threadStatus.getInt(self) == State.RUNNABLE.value; - setState(self, meta, state); - checkDeprecatedState(meta, self); - } - - public static void toRunnable(StaticObject self, Meta meta, State state) { - assert state == State.RUNNABLE; - try { - checkDeprecatedState(meta, self); - } finally { - setState(self, meta, state); - } - } - - private static void setState(StaticObject self, Meta meta, State state) { - meta.java_lang_Thread_threadStatus.setInt(self, state.value); - } - - @TruffleBoundary - public static void checkDeprecatedState(Meta meta, StaticObject thread) { - EspressoContext context = meta.getContext(); - assert thread == context.getCurrentThread(); - if (context.shouldCheckStop()) { - KillStatus status = getKillStatus(thread); - switch (status) { - case NORMAL: - case EXITING: - case KILLED: - break; - case KILL: - if (context.isClosing()) { - // Give some leeway during closing. - setThreadStop(thread, KillStatus.KILLED); - } else { - setThreadStop(thread, KillStatus.NORMAL); - } - // check if death cause throwable is set, if not throw ThreadDeath - StaticObject deathThrowable = (StaticObject) getDeathThrowable(thread); - throw deathThrowable != null ? meta.throwException(deathThrowable) : meta.throwException(meta.java_lang_ThreadDeath); - case SHUTDOWN: - // This thread refuses to stop. Send a host exception. - // throw getMeta().throwEx(ThreadDeath.class); - assert context.isClosing(); - throw new EspressoExitException(context.getExitStatus()); - } - } - if (context.shouldCheckSuspend()) { - trySuspend(thread); - } - } - @Substitution(isTrivial = true) public static @JavaType(Thread.class) StaticObject currentThread(@Inject EspressoContext context) { return context.getCurrentThread(); @@ -182,72 +113,27 @@ abstract static class Start0 extends SubstitutionNode { @TruffleBoundary void doCached(@JavaType(Thread.class) StaticObject self, @Bind("getContext()") EspressoContext context, - @Cached("create(context.getMeta().java_lang_Thread_exit.getCallTarget())") DirectCallNode threadExit) { + @Cached("create(context.getMeta().java_lang_Thread_exit.getCallTarget())") DirectCallNode threadExit, + @Cached("create(context.getMeta().java_lang_Thread_dispatchUncaughtException.getCallTarget())") DirectCallNode dispatchUncaught) { Meta meta = context.getMeta(); + ThreadsAccess threadAccess = context.getThreadAccess(); if (context.multiThreadingEnabled()) { // Thread.start() is synchronized. - KillStatus killStatus = getKillStatus(self); - if (killStatus != null || context.isClosing()) { - - self.getLock().lock(); - try { - meta.java_lang_Thread_threadStatus.setInt(self, State.TERMINATED.value); - // Notify waiting threads you were terminated - self.getLock().signalAll(); - } finally { - self.getLock().unlock(); - } - + if (threadAccess.terminateIfStillborn(self)) { return; } - setThreadStop(self, KillStatus.NORMAL); - if (getSuspendLock(self) == null) { - initSuspendLock(self); - } - Thread hostThread = context.getEnv().createThread(new Runnable() { - @Override - public void run() { - try { - context.getVM().attachThread(Thread.currentThread()); - try { - // Execute the payload - self.getKlass().vtableLookup(meta.java_lang_Thread_run.getVTableIndex()).invokeDirect(self); - checkDeprecatedState(meta, self); - } catch (EspressoException uncaught) { - meta.java_lang_Thread_dispatchUncaughtException.invokeDirect(self, uncaught.getExceptionObject()); - } - } catch (EspressoExitException exit) { - /* Suppress */ - } finally { - terminate(self, threadExit, meta); - if (context.isClosing()) { - // Ignore exceptions that arise during closing. - return; - } - } - } - }); - - meta.HIDDEN_HOST_THREAD.setHiddenObject(self, hostThread); - hostThread.setDaemon(meta.java_lang_Thread_daemon.getBoolean(self)); - meta.java_lang_Thread_threadStatus.setInt(self, State.RUNNABLE.value); - hostThread.setPriority(meta.java_lang_Thread_priority.getInt(self)); - if (isInterrupted(self, false)) { - hostThread.interrupt(); - } - context.registerThread(hostThread, self); - String guestName = Target_java_lang_Thread.getThreadName(meta, self); + Thread hostThread = threadAccess.createJavaThread(self, threadExit, dispatchUncaught); context.getLogger().fine(() -> { - long guestId = Target_java_lang_Thread.getThreadId(meta, self); + String guestName = threadAccess.getThreadName(self); + long guestId = threadAccess.getThreadId(self); return String.format("Thread.start0: [HOST:%s, %d], [GUEST:%s, %d]", hostThread.getName(), hostThread.getId(), guestName, guestId); }); - hostThread.setName(guestName); hostThread.start(); } else { String reason = context.getMultiThreadingDisabledReason(); Klass threadKlass = self.getKlass(); EspressoContext.get(null).getLogger().warning(() -> { - String guestName = Target_java_lang_Thread.getThreadName(meta, self); + String guestName = threadAccess.getThreadName(self); String className = threadKlass.getExternalName(); return "Thread.start() called on " + className + " / " + guestName + " but thread support is disabled: " + reason; }); @@ -270,51 +156,6 @@ private static boolean isSystemInnocuousThread(StaticObject thread, Meta meta) { return true; } - public static void terminate(StaticObject thread, Meta meta) { - terminate(thread, null, meta); - } - - private static void terminate(@JavaType(Thread.class) StaticObject self, DirectCallNode threadExit, Meta meta) { - setThreadStop(self, KillStatus.EXITING); - try { - if (threadExit != null) { - threadExit.call(self); - } else { - meta.java_lang_Thread_exit.invokeDirect(self); - } - } catch (EspressoException | EspressoExitException e) { - // just drop it - } - self.getLock().lock(); - try { - meta.java_lang_Thread_threadStatus.setInt(self, State.TERMINATED.value); - // Notify waiting threads you are done working - self.getLock().signalAll(); - } finally { - self.getLock().unlock(); - } - - EspressoContext context = meta.getContext(); - // Cleanup. - context.unregisterThread(self); - } - - public static String getThreadName(Meta meta, StaticObject thread) { - if (thread == null) { - return ""; - } else { - return meta.toHostString(meta.java_lang_Thread_name.getObject(thread)); - } - } - - public static long getThreadId(Meta meta, StaticObject thread) { - if (thread == null) { - return -1; - } else { - return (long) meta.java_lang_Thread_tid.get(thread); - } - } - @TruffleBoundary @Substitution(isTrivial = true) public static void yield() { @@ -323,9 +164,10 @@ public static void yield() { @SuppressWarnings("unused") @Substitution(hasReceiver = true) - public static void setPriority0(@JavaType(Thread.class) StaticObject self, int newPriority) { + public static void setPriority0(@JavaType(Thread.class) StaticObject self, int newPriority, + @Inject EspressoContext context) { // Priority is set in the guest field in Thread.setPriority(). - Thread hostThread = getHostFromGuestThread(self); + Thread hostThread = context.getThreadAccess().getHost(self); if (hostThread == null) { return; } @@ -333,9 +175,9 @@ public static void setPriority0(@JavaType(Thread.class) StaticObject self, int n } @Substitution(hasReceiver = true) - public static boolean isAlive(@JavaType(Thread.class) StaticObject self) { - int state = self.getKlass().getMeta().java_lang_Thread_threadStatus.getInt(self); - return state != State.NEW.value && state != State.TERMINATED.value; + public static boolean isAlive(@JavaType(Thread.class) StaticObject self, + @Inject EspressoContext context) { + return context.getThreadAccess().isAlive(self); } @Substitution(hasReceiver = true) @@ -372,256 +214,67 @@ public static boolean holdsLock(@JavaType(Object.class) StaticObject object, @In public static void sleep(long millis, @Inject Meta meta) { StaticObject thread = meta.getContext().getCurrentThread(); try { - fromRunnable(thread, meta, State.TIMED_WAITING); + meta.getThreadAccess().fromRunnable(thread, State.TIMED_WAITING); Thread.sleep(millis); } catch (InterruptedException e) { - setInterrupt(thread, false); + meta.getThreadAccess().clearInterruptStatus(thread); throw meta.throwExceptionWithMessage(meta.java_lang_InterruptedException, e.getMessage()); } catch (IllegalArgumentException e) { throw meta.throwExceptionWithMessage(meta.java_lang_IllegalArgumentException, e.getMessage()); } finally { - toRunnable(thread, meta, State.RUNNABLE); + meta.getThreadAccess().toRunnable(thread); } } - public static void setInterrupt(StaticObject self, boolean value) { - self.getKlass().getMeta().HIDDEN_INTERRUPTED.setBoolean(self, value, true); - } - - static boolean checkInterrupt(StaticObject self) { - return self.getKlass().getMeta().HIDDEN_INTERRUPTED.getBoolean(self, true); - } - @TruffleBoundary @Substitution(hasReceiver = true) - public static void interrupt0(@JavaType(Object.class) StaticObject self) { - Thread hostThread = getHostFromGuestThread(self); - if (hostThread == null) { - return; - } - if (self.getKlass().getMeta().getJavaVersion().java13OrEarlier()) { - // Starting from JDK 14, the interrupted status is set in java code. - setInterrupt(self, true); - } - hostThread.interrupt(); + public static void interrupt0(@JavaType(Object.class) StaticObject self, + @Inject EspressoContext context) { + context.getThreadAccess().interrupt(self); } @Substitution - public static void clearInterruptEvent() { - Thread.interrupted(); // Clear host interruption + public static void clearInterruptEvent(@Inject EspressoContext context) { + context.getThreadAccess().clearInterruptEvent(); } @TruffleBoundary @Substitution(hasReceiver = true, versionFilter = VersionFilter.Java13OrEarlier.class) - public static boolean isInterrupted(@JavaType(Thread.class) StaticObject self, boolean clear) { - boolean result = checkInterrupt(self); - if (clear) { - Thread hostThread = getHostFromGuestThread(self); - EspressoError.guarantee(hostThread == Thread.currentThread(), "Thread#isInterrupted(true) is only supported for the current thread."); - if (hostThread != null && hostThread.isInterrupted()) { - Thread.interrupted(); - } - setInterrupt(self, false); - } - return result; + public static boolean isInterrupted(@JavaType(Thread.class) StaticObject self, boolean clear, + @Inject EspressoContext context) { + return context.getThreadAccess().isInterrupted(self, clear); } @TruffleBoundary @SuppressWarnings({"unused"}) @Substitution(hasReceiver = true) - public static void resume0(@JavaType(Object.class) StaticObject self) { - SuspendLock lock = getSuspendLock(self); - if (lock == null) { - return; - } - synchronized (lock) { - lock.shouldSuspend = false; - lock.notifyAll(); - } + public static void resume0(@JavaType(Object.class) StaticObject self, + @Inject EspressoContext context) { + context.getThreadAccess().resume(self); } @TruffleBoundary @SuppressWarnings({"unused"}) @Substitution(hasReceiver = true) - public static void suspend0(@JavaType(Object.class) StaticObject toSuspend) { - toSuspend.getKlass().getContext().invalidateNoSuspend("Calling Thread.suspend()"); - SuspendLock lock = getSuspendLock(toSuspend); - if (lock == null) { - if (!isAlive(toSuspend)) { - return; - } - lock = initSuspendLock(toSuspend); - } - suspendHandshake(lock, toSuspend.getKlass().getMeta(), toSuspend); + public static void suspend0(@JavaType(Object.class) StaticObject toSuspend, + @Inject EspressoContext context) { + context.invalidateNoSuspend("Calling Thread.suspend()"); + context.getThreadAccess().suspend(toSuspend); } @TruffleBoundary @Substitution(hasReceiver = true) - public static void stop0(@JavaType(Object.class) StaticObject self, @JavaType(Object.class) StaticObject throwable) { - self.getKlass().getContext().invalidateNoThreadStop("Calling thread.stop()"); - killThread(self); - setInterrupt(self, true); - setDeathThrowable(self, throwable); - Thread hostThread = getHostFromGuestThread(self); - if (hostThread == null) { - return; - } - hostThread.interrupt(); + public static void stop0(@JavaType(Object.class) StaticObject self, @JavaType(Object.class) StaticObject throwable, + @Inject EspressoContext context) { + context.invalidateNoThreadStop("Calling thread.stop()"); + context.getThreadAccess().stop(self, throwable); } @TruffleBoundary @Substitution(hasReceiver = true) public static void setNativeName(@JavaType(Object.class) StaticObject self, @JavaType(String.class) StaticObject name, @Inject Meta meta) { - Thread hostThread = getHostFromGuestThread(self); + Thread hostThread = meta.getThreadAccess().getHost(self); hostThread.setName(meta.toHostString(name)); } - - public static Thread getHostFromGuestThread(@JavaType(Object.class) StaticObject self) { - return (Thread) self.getKlass().getMeta().HIDDEN_HOST_THREAD.getHiddenObject(self); - } - - public static boolean checkThreadStatus(StaticObject thread, KillStatus status) { - KillStatus stop = (KillStatus) thread.getKlass().getMeta().HIDDEN_DEATH.getHiddenObject(thread); - return stop != null && stop == status; - } - - public static void setThreadStop(StaticObject thread, KillStatus value) { - thread.getKlass().getMeta().HIDDEN_DEATH.setHiddenObject(thread, value); - } - - /** - * Hints the thread that it should throw a ThreadDeath error whenever he can. - */ - public static void killThread(StaticObject thread) { - setThreadStop(thread, KillStatus.KILL); - } - - /** - * Forces the thread to stop execution at the next safepoint by throwing a host exit exception. - */ - public static void forceKillThread(StaticObject thread) { - setThreadStop(thread, KillStatus.SHUTDOWN); - } - - public static void setDeathThrowable(StaticObject self, Object deathThrowable) { - self.getKlass().getMeta().HIDDEN_DEATH_THROWABLE.setHiddenObject(self, deathThrowable); - } - - public static Object getDeathThrowable(StaticObject self) { - return self.getKlass().getMeta().HIDDEN_DEATH_THROWABLE.getHiddenObject(self); - } - - public static KillStatus getKillStatus(StaticObject thread) { - return (KillStatus) thread.getKlass().getMeta().HIDDEN_DEATH.getHiddenObject(thread); - } - - public enum KillStatus { - /** - * Normal state: no Thread.stop() called, or ThreadDeath has already been thrown. - */ - NORMAL, - /** - * Thread will throw an asynchronous ThreadDeath whenever possible. - */ - KILL, - /** - * Was killed, but we are in context closing. If the thread is alive for a while in that - * state, it will be considered uncooperative. - */ - KILLED, - /** - * Was killed, and is calling Thread.exit(). Ignore further kill signals. - */ - EXITING, - /** - * Thread is uncooperative: needs to be killed with a host exception. Very dangerous state - * to be in. - */ - SHUTDOWN - } - - public static class SuspendLock { - private Object notifier = new Object(); - - private volatile boolean shouldSuspend; - private volatile boolean threadSuspended; - - public boolean shouldSuspend() { - return shouldSuspend; - } - - public boolean targetThreadIsSuspended() { - return threadSuspended; - } - } - - private static SuspendLock getSuspendLock(@JavaType(Object.class) StaticObject self) { - return (SuspendLock) self.getKlass().getMeta().HIDDEN_SUSPEND_LOCK.getHiddenObject(self); - } - - /** - * Synchronizes on Target_ class to avoid deadlock when locking on thread object. - */ - private static synchronized SuspendLock initSuspendLock(@JavaType(Object.class) StaticObject self) { - SuspendLock lock = getSuspendLock(self); - if (lock == null) { - lock = new SuspendLock(); - self.getKlass().getMeta().HIDDEN_SUSPEND_LOCK.setHiddenObject(self, lock); - } - return lock; - } - - public static boolean isSuspended(StaticObject self) { - assert getSuspendLock(self) != null; - return getSuspendLock(self).shouldSuspend(); - } - - @TruffleBoundary - public static void trySuspend(StaticObject self) { - SuspendLock lock = getSuspendLock(self); - if (lock == null) { - return; - } - synchronized (lock) { - if (lock.shouldSuspend()) { - synchronized (lock.notifier) { - lock.threadSuspended = true; - lock.notifier.notifyAll(); - } - } - while (lock.shouldSuspend()) { - try { - lock.wait(); - - } catch (InterruptedException e) { - } - } - } - lock.threadSuspended = false; - } - - @TruffleBoundary - private static void suspendHandshake(SuspendLock lock, Meta meta, StaticObject toSuspend) { - Object notifier = lock.notifier; - boolean wasInterrupted = false; - while (!lock.targetThreadIsSuspended()) { - lock.shouldSuspend = true; - try { - synchronized (notifier) { - if (meta.java_lang_Thread_threadStatus.getInt(toSuspend) == State.RUNNABLE.value) { - notifier.wait(); - } else { - break; - } - } - } catch (InterruptedException e) { - /* Thread.suspend() is not supposed to be interrupted */ - wasInterrupted = true; - } - } - if (wasInterrupted) { - meta.getContext().interruptThread(meta.getContext().getCurrentThread()); - } - } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_reflect_ProxyGenerator.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_reflect_ProxyGenerator.java index 5e2aaa7bc249..0f0b5f7db69e 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_reflect_ProxyGenerator.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_reflect_ProxyGenerator.java @@ -33,7 +33,7 @@ @EspressoSubstitutions public final class Target_java_lang_reflect_ProxyGenerator { - @Substitution(versionFilter = VersionFilter.Java8OrEarlier.class) + @Substitution(versionFilter = VersionFilter.Java9OrLater.class) abstract static class GenerateProxyClass extends SubstitutionNode { abstract @JavaType(byte[].class) StaticObject execute( diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_misc_Unsafe.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_misc_Unsafe.java index 99576877207c..d93a4247f92d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_misc_Unsafe.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_misc_Unsafe.java @@ -52,7 +52,7 @@ import com.oracle.truffle.espresso.meta.MetaUtil; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.StaticObject; -import com.oracle.truffle.espresso.substitutions.Target_java_lang_Thread.State; +import com.oracle.truffle.espresso.threads.State; import com.oracle.truffle.espresso.vm.InterpreterToVM; import com.oracle.truffle.espresso.vm.UnsafeAccess; @@ -1376,12 +1376,12 @@ public static void park(@JavaType(Unsafe.class) StaticObject self, boolean isAbs EspressoContext context = meta.getContext(); StaticObject thread = context.getCurrentThread(); - if (Target_java_lang_Thread.checkInterrupt(thread)) { + if (meta.getThreadAccess().isInterrupted(thread, false)) { return; } Unsafe unsafe = UnsafeAccess.getIfAllowed(meta); - Target_java_lang_Thread.fromRunnable(thread, meta, time > 0 ? State.TIMED_WAITING : State.WAITING); + meta.getThreadAccess().fromRunnable(thread, time > 0 ? State.TIMED_WAITING : State.WAITING); Thread hostThread = Thread.currentThread(); Object blocker = LockSupport.getBlocker(hostThread); Field parkBlocker = meta.java_lang_Thread.lookupDeclaredField(Symbol.Name.parkBlocker, Type.java_lang_Object); @@ -1393,7 +1393,7 @@ public static void park(@JavaType(Unsafe.class) StaticObject self, boolean isAbs parkBoundary(self, isAbsolute, time, meta); - Target_java_lang_Thread.toRunnable(thread, meta, State.RUNNABLE); + meta.getThreadAccess().toRunnable(thread); unsafe.putObject(hostThread, PARK_BLOCKER_OFFSET, blocker); } @@ -1417,7 +1417,7 @@ public static void parkBoundary(@SuppressWarnings("unused") @JavaType(Unsafe.cla @Substitution(hasReceiver = true) public static void unpark(@SuppressWarnings("unused") @JavaType(Unsafe.class) StaticObject self, @JavaType(Object.class) StaticObject thread, @Inject Meta meta) { - Thread hostThread = (Thread) meta.HIDDEN_HOST_THREAD.getHiddenObject(thread); + Thread hostThread = meta.getThreadAccess().getHost(thread); UnsafeAccess.getIfAllowed(meta).unpark(hostThread); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_reflect_NativeMethodAccessorImpl.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_reflect_NativeMethodAccessorImpl.java index 4919e1404fd2..c243dd436f6d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_reflect_NativeMethodAccessorImpl.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_reflect_NativeMethodAccessorImpl.java @@ -253,7 +253,7 @@ public static Object checkAndWiden(Meta meta, StaticObject arg, Klass targetKlas Method reflectedMethod = m; if (reflectedMethod.isRemovedByRedefition()) { - reflectedMethod = ClassRedefinition.handleRemovedMethod(reflectedMethod, reflectedMethod.isStatic() ? reflectedMethod.getDeclaringKlass() : receiver.getKlass(), receiver); + reflectedMethod = ClassRedefinition.handleRemovedMethod(reflectedMethod, reflectedMethod.isStatic() ? reflectedMethod.getDeclaringKlass() : receiver.getKlass()); } Method method; // actual method to invoke diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/VersionFilter.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/VersionFilter.java index f75994215630..1cbcba54b238 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/VersionFilter.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/VersionFilter.java @@ -53,6 +53,18 @@ public boolean isValidFor(JavaVersion version) { } } + final class Java9OrLater implements VersionFilter { + public static final Java9OrLater INSTANCE = new Java9OrLater(); + + private Java9OrLater() { + } + + @Override + public boolean isValidFor(JavaVersion version) { + return version.java9OrLater(); + } + } + final class Java11OrEarlier implements VersionFilter { public static final Java11OrEarlier INSTANCE = new Java11OrEarlier(); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoThreadManager.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/EspressoThreadRegistry.java similarity index 88% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoThreadManager.java rename to espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/EspressoThreadRegistry.java index 49bc570f6253..90c12cc69cf7 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoThreadManager.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/EspressoThreadRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.runtime; +package com.oracle.truffle.espresso.threads; import java.util.ArrayList; import java.util.Collections; @@ -35,16 +35,16 @@ import com.oracle.truffle.espresso.EspressoLanguage; import com.oracle.truffle.espresso.descriptors.Symbol; import com.oracle.truffle.espresso.impl.ContextAccess; -import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.impl.SuppressFBWarnings; import com.oracle.truffle.espresso.meta.Meta; -import com.oracle.truffle.espresso.substitutions.Target_java_lang_Thread; +import com.oracle.truffle.espresso.runtime.EspressoContext; +import com.oracle.truffle.espresso.runtime.StaticObject; import com.oracle.truffle.espresso.vm.VM; -class EspressoThreadManager implements ContextAccess { +public final class EspressoThreadRegistry implements ContextAccess { private static final int DEFAULT_THREAD_ARRAY_SIZE = 8; - private final TruffleLogger logger = TruffleLogger.getLogger(EspressoLanguage.ID, EspressoThreadManager.class); + private final TruffleLogger logger = TruffleLogger.getLogger(EspressoLanguage.ID, EspressoThreadRegistry.class); private final EspressoContext context; private final Set activeThreads = Collections.newSetFromMap(new ConcurrentHashMap<>()); @@ -56,7 +56,7 @@ public EspressoContext getContext() { return context; } - EspressoThreadManager(EspressoContext context) { + public EspressoThreadRegistry(EspressoContext context) { this.context = context; } @@ -109,8 +109,8 @@ private void registerMainThread(Thread thread, StaticObject self) { activeThreads.add(self); } - final AtomicLong createdThreadCount = new AtomicLong(); - final AtomicLong peakThreadCount = new AtomicLong(); + public final AtomicLong createdThreadCount = new AtomicLong(); + public final AtomicLong peakThreadCount = new AtomicLong(); public void registerThread(Thread host, StaticObject guest) { activeThreads.add(guest); @@ -158,12 +158,12 @@ public long applyAsLong(long oldPeak) { @SuppressFBWarnings(value = "NN", justification = "Removing a thread from the active set is the state change we need.") public void unregisterThread(StaticObject thread) { logger.fine(() -> { - String guestName = Target_java_lang_Thread.getThreadName(getMeta(), thread); - long guestId = Target_java_lang_Thread.getThreadId(getMeta(), thread); + String guestName = getThreadAccess().getThreadName(thread); + long guestId = getThreadAccess().getThreadId(thread); return String.format("unregisterThread([GUEST:%s, %d])", guestName, guestId); }); activeThreads.remove(thread); - Thread hostThread = (Thread) getMeta().HIDDEN_HOST_THREAD.getHiddenObject(thread); + Thread hostThread = getThreadAccess().getHost(thread); int id = Math.toIntExact(hostThread.getId()); synchronized (activeThreadLock) { if (id == mainThreadId) { @@ -178,7 +178,7 @@ public void unregisterThread(StaticObject thread) { } else { Object[] threads = guestThreads; int threadIndex = getThreadIndex(id, threads); - if (Target_java_lang_Thread.isAlive(thread)) { + if (getThreadAccess().isAlive(thread)) { assert threads[threadIndex] == thread; threads[threadIndex] = null; } else { @@ -267,7 +267,6 @@ public StaticObject createGuestThreadFromHost(Thread hostThread, Meta meta, VM v // Allow guest Thread.currentThread() to work. meta.java_lang_Thread_priority.setInt(guestThread, Thread.NORM_PRIORITY); meta.HIDDEN_HOST_THREAD.setHiddenObject(guestThread, Thread.currentThread()); - meta.HIDDEN_DEATH.setHiddenObject(guestThread, Target_java_lang_Thread.KillStatus.NORMAL); // register the new guest thread registerThread(hostThread, guestThread); @@ -277,14 +276,14 @@ public StaticObject createGuestThreadFromHost(Thread hostThread, Meta meta, VM v } else { meta.java_lang_Thread_init_ThreadGroup_String.invokeDirect(guestThread, threadGroup, meta.toGuestString(name)); } - meta.java_lang_Thread_threadStatus.setInt(guestThread, Target_java_lang_Thread.State.RUNNABLE.value); + meta.java_lang_Thread_threadStatus.setInt(guestThread, State.RUNNABLE.value); // now add to the main thread group meta.java_lang_ThreadGroup_add.invokeDirect(threadGroup, guestThread); logger.fine(() -> { - String guestName = Target_java_lang_Thread.getThreadName(getMeta(), guestThread); - long guestId = Target_java_lang_Thread.getThreadId(getMeta(), guestThread); + String guestName = getThreadAccess().getThreadName(guestThread); + long guestId = getThreadAccess().getThreadId(guestThread); return String.format("createGuestThreadFromHost: [HOST:%s, %d], [GUEST:%s, %d]", hostThread.getName(), hostThread.getId(), guestName, guestId); }); @@ -306,7 +305,6 @@ public void createMainThread(Meta meta) { // Allow guest Thread.currentThread() to work. meta.java_lang_Thread_priority.setInt(mainThread, Thread.NORM_PRIORITY); meta.HIDDEN_HOST_THREAD.setHiddenObject(mainThread, hostThread); - meta.HIDDEN_DEATH.setHiddenObject(mainThread, Target_java_lang_Thread.KillStatus.NORMAL); mainThreadGroup = meta.java_lang_ThreadGroup.allocateInstance(); registerMainThread(hostThread, mainThread); @@ -323,15 +321,15 @@ public void createMainThread(Meta meta) { .invokeDirect(mainThread, /* group */ mainThreadGroup, /* name */ meta.toGuestString("main")); - meta.java_lang_Thread_threadStatus.setInt(mainThread, Target_java_lang_Thread.State.RUNNABLE.value); + meta.java_lang_Thread_threadStatus.setInt(mainThread, State.RUNNABLE.value); // Notify native backend about main thread. getNativeAccess().prepareThread(); mainThreadCreated = true; logger.fine(() -> { - String guestName = Target_java_lang_Thread.getThreadName(getMeta(), mainThread); - long guestId = Target_java_lang_Thread.getThreadId(getMeta(), mainThread); + String guestName = getThreadAccess().getThreadName(mainThread); + long guestId = getThreadAccess().getThreadId(mainThread); return String.format("createMainThread: [HOST:%s, %d], [GUEST:%s, %d]", hostThread.getName(), hostThread.getId(), guestName, guestId); }); } @@ -370,8 +368,8 @@ private void refactorGuestThreads(int id, StaticObject self) { for (int i = 1; i < oldThreads.length; i++) { if (oldThreads[i] != null) { StaticObject guestThread = (StaticObject) oldThreads[i]; - if (Target_java_lang_Thread.isAlive(guestThread)) { - Thread hostThread = Target_java_lang_Thread.getHostFromGuestThread(guestThread); + if (getThreadAccess().isAlive(guestThread)) { + Thread hostThread = getThreadAccess().getHost(guestThread); int hostID = (int) hostThread.getId(); if (hostID < minID) { minID = hostID; @@ -398,7 +396,7 @@ private void refactorGuestThreads(int id, StaticObject self) { int newOffset = minID - 1; newThreads[0] = newOffset; for (StaticObject guestThread : toRelocate) { - int hostId = (int) Target_java_lang_Thread.getHostFromGuestThread(guestThread).getId(); + int hostId = (int) context.getThreadAccess().getHost(guestThread).getId(); newThreads[hostId - newOffset] = guestThread; } newThreads[id - newOffset] = self; @@ -409,11 +407,4 @@ private void refactorGuestThreads(int id, StaticObject self) { private static int getThreadIndex(int id, Object[] threads) { return id - (int) threads[0]; } - - public void interruptThread(StaticObject guestThread) { - assert guestThread != null && getMeta().java_lang_Thread.isAssignableFrom(guestThread.getKlass()); - Method interruptMethod = guestThread.getKlass().vtableLookup(getMeta().java_lang_Thread_interrupt.getVTableIndex()); - assert interruptMethod != null; - interruptMethod.invokeDirect(guestThread); - } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/GuestRunnable.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/GuestRunnable.java new file mode 100644 index 000000000000..cb47044fa949 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/GuestRunnable.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.truffle.espresso.threads; + +import com.oracle.truffle.api.nodes.DirectCallNode; +import com.oracle.truffle.espresso.runtime.EspressoContext; +import com.oracle.truffle.espresso.runtime.EspressoException; +import com.oracle.truffle.espresso.runtime.EspressoExitException; +import com.oracle.truffle.espresso.runtime.StaticObject; + +/** + * The payload of the host thread executing a guest {@linkplain #thread thread}. + * + * When started, the host thread: + *
      + *
    • Attached itself to the context.
    • + *
    • Fetches the guest {@link Thread#run()} methods and executes it.
    • + *
    • If an exception escapes the guest thread, call + * {@code Thread#dispatchUncaughtException(Throwable)}.
    • + *
    • Upon completion, {@link ThreadsAccess#terminate(StaticObject, DirectCallNode) terminates} the + * guest thread.
    • + *
    + */ +final class GuestRunnable implements Runnable { + private final EspressoContext context; + private final StaticObject thread; + private final DirectCallNode exit; + private final DirectCallNode dispatchUncaught; + + GuestRunnable(EspressoContext context, StaticObject thread, DirectCallNode exit, DirectCallNode dispatchUncaught) { + this.context = context; + this.thread = thread; + this.exit = exit; + this.dispatchUncaught = dispatchUncaught; + } + + @Override + public void run() { + try { + context.getVM().attachThread(Thread.currentThread()); + try { + // Execute the payload + context.getThreadAccess().checkDeprecation(); + thread.getKlass().vtableLookup(context.getMeta().java_lang_Thread_run.getVTableIndex()).invokeDirect(thread); + context.getThreadAccess().checkDeprecation(); + } catch (EspressoException uncaught) { + dispatchUncaught.call(thread, uncaught.getExceptionObject()); + } + } catch (EspressoExitException exitException) { + /* Suppress */ + } finally { + context.getThreadAccess().terminate(thread, exit); + if (context.isClosing()) { + // Ignore exceptions that arise during closing. + return; + } + } + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/KillStatus.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/KillStatus.java new file mode 100644 index 000000000000..4dd766925ead --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/KillStatus.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.truffle.espresso.threads; + +public enum KillStatus { + /** + * Normal state: no Thread.stop() called, or ThreadDeath has already been thrown. + */ + NORMAL, + /** + * Thread will throw an asynchronous ThreadDeath whenever possible. + */ + STOP, + /** + * Thread is terminated, and is calling Thread.exit(). Ignore further stop signals. + */ + EXITING, + /** + * Thread is uncooperative: needs to be killed with a host exception. Unrecoverable state. + */ + KILL +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK15OrLater.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/State.java similarity index 63% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK15OrLater.java rename to espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/State.java index 91c8331a6548..1fdbe55abc01 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK15OrLater.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/State.java @@ -1,12 +1,10 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. + * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -22,15 +20,20 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk; -import java.util.function.BooleanSupplier; +package com.oracle.truffle.espresso.threads; -import org.graalvm.compiler.serviceprovider.JavaVersionUtil; +public enum State { + NEW(0), + RUNNABLE(4), + BLOCKED(1024), + WAITING(16), + TIMED_WAITING(32), + TERMINATED(2); -public class JDK15OrLater implements BooleanSupplier { - @Override - public boolean getAsBoolean() { - return JavaVersionUtil.JAVA_SPEC >= 15; + public final int value; + + State(int value) { + this.value = value; } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/SuspendLock.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/SuspendLock.java new file mode 100644 index 000000000000..cf132c5e3494 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/SuspendLock.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.truffle.espresso.threads; + +import com.oracle.truffle.espresso.runtime.StaticObject; + +public final class SuspendLock { + private final Object handshakeLock = new Object() { + }; + private final ThreadsAccess access; + private final StaticObject thread; + + private volatile boolean shouldSuspend; + private volatile boolean threadSuspended; + + public SuspendLock(ThreadsAccess access, StaticObject thread) { + this.access = access; + this.thread = thread; + } + + public void suspend() { + if (access.getHost(thread) == Thread.currentThread()) { + // No need for handshake + shouldSuspend = true; + selfSuspend(); + } else { + suspendHandshake(); + } + } + + public synchronized void selfSuspend() { + while (shouldSuspend()) { + notifySuspended(); + try { + wait(); + } catch (InterruptedException e) { + /* spin back */ + } + } + threadSuspended = false; + } + + public synchronized void resume() { + if (shouldSuspend()) { + shouldSuspend = false; + notifyAll(); + } + } + + private boolean shouldSuspend() { + return shouldSuspend; + } + + private boolean isSuspended() { + return threadSuspended; + } + + private void suspendHandshake() { + boolean wasInterrupted = false; + while (!isSuspended()) { + shouldSuspend = true; + try { + synchronized (handshakeLock) { + if (!access.isAlive(thread)) { + // If thread terminates, we don't want to wait forever + handshakeLock.wait(100); + } else { + break; + } + } + } catch (InterruptedException e) { + /* Thread.suspend() is not supposed to be interrupted */ + wasInterrupted = true; + } + } + if (wasInterrupted) { + // Re-interrupt ourselves + Thread.currentThread().interrupt(); + } + } + + private void notifySuspended() { + synchronized (handshakeLock) { + threadSuspended = true; + handshakeLock.notifyAll(); + } + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/ThreadsAccess.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/ThreadsAccess.java new file mode 100644 index 000000000000..395e5d29592a --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/ThreadsAccess.java @@ -0,0 +1,459 @@ +/* + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.truffle.espresso.threads; + +import static com.oracle.truffle.espresso.threads.KillStatus.EXITING; +import static com.oracle.truffle.espresso.threads.KillStatus.KILL; +import static com.oracle.truffle.espresso.threads.KillStatus.NORMAL; +import static com.oracle.truffle.espresso.threads.KillStatus.STOP; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.nodes.DirectCallNode; +import com.oracle.truffle.espresso.impl.ContextAccess; +import com.oracle.truffle.espresso.impl.Method; +import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.meta.Meta; +import com.oracle.truffle.espresso.runtime.EspressoContext; +import com.oracle.truffle.espresso.runtime.EspressoException; +import com.oracle.truffle.espresso.runtime.EspressoExitException; +import com.oracle.truffle.espresso.runtime.StaticObject; + +/** + * Provides bridges to guest world thread implementation. + */ +public final class ThreadsAccess implements ContextAccess { + + private final Meta meta; + private final EspressoContext context; + + public ThreadsAccess(Meta meta) { + this.meta = meta; + this.context = meta.getContext(); + } + + @Override + public EspressoContext getContext() { + return context; + } + + public String getThreadName(StaticObject thread) { + if (thread == null) { + return ""; + } else { + return meta.toHostString(meta.java_lang_Thread_name.getObject(thread)); + } + } + + public long getThreadId(StaticObject thread) { + if (thread == null) { + return -1; + } else { + return (long) meta.java_lang_Thread_tid.get(thread); + } + } + + /** + * Returns the host thread associated with this guest thread, or null if the guest thread has + * not yet been registered. + */ + public Thread getHost(StaticObject guest) { + return (Thread) meta.HIDDEN_HOST_THREAD.getHiddenObject(guest); + } + + // region thread state transition + + public void fromRunnable(StaticObject self, State state) { + assert meta.java_lang_Thread_threadStatus.getInt(self) == State.RUNNABLE.value; + setState(self, state); + checkDeprecation(); + } + + public void toRunnable(StaticObject self) { + try { + checkDeprecation(); + } finally { + setState(self, State.RUNNABLE); + } + } + + private void setState(StaticObject self, State state) { + meta.java_lang_Thread_threadStatus.setInt(self, state.value); + } + + // endregion thread state transition + + // region thread control + + /** + * Implements support for thread deprecated methods ({@code Thread#stop()}, + * {@code Thread#suspend()}, {@code Thread#resume()}). + *

    + * The following performance concerns are to be considered: + *

      + *
    • If these deprecated methods are never called, this method should entirely fold.
    • + *
    • When called for the first time, a very large portion of the compiled code will be + * invalidated.
    • + *
    • After being called for the first time, in most cases, this method should amount to + * getting the current thread and reading a field
    • + *
    + */ + public void checkDeprecation() { + // TODO: safepoints + if (!context.shouldCheckDeprecationStatus()) { + return; + } + StaticObject current = context.getCurrentThread(); + DeprecationSupport support = getDeprecationSupport(current, false); + if (support == null) { + return; + } + if (context.shouldCheckStop()) { + support.handleStop(meta); + } + if (context.shouldCheckSuspend()) { + support.handleSuspend(); + } + } + + /** + * Lookups and calls the guest Thread.interrupt() method. + */ + public void interruptThread(StaticObject guestThread) { + assert guestThread != null && getMeta().java_lang_Thread.isAssignableFrom(guestThread.getKlass()); + // Thread.interrupt is non-final. + Method interruptMethod = guestThread.getKlass().vtableLookup(getMeta().java_lang_Thread_interrupt.getVTableIndex()); + assert interruptMethod != null; + interruptMethod.invokeDirect(guestThread); + } + + /** + * Implementation of {@link Thread#isInterrupted()}. + */ + public boolean isInterrupted(StaticObject guest, boolean clear) { + boolean isInterrupted = meta.HIDDEN_INTERRUPTED.getBoolean(guest, true); + if (clear) { + Thread host = getHost(guest); + EspressoError.guarantee(host == Thread.currentThread(), "Thread#isInterrupted(true) is only supported for the current thread."); + if (host != null && host.isInterrupted()) { + Thread.interrupted(); + } + clearInterruptStatus(guest); + } + return isInterrupted; + } + + /** + * Implementation of {@link Thread#interrupt()}. + */ + public void interrupt(StaticObject guest) { + if (context.getJavaVersion().java13OrEarlier()) { + // In JDK 13+, the interrupted status is set in java code. + meta.HIDDEN_INTERRUPTED.setBoolean(guest, true, true); + } + Thread host = getHost(guest); + if (host != null) { + host.interrupt(); + } + } + + /** + * Implementation of {@code Thread.clearInterruptEvent} (JDK 13+). + */ + public void clearInterruptEvent() { + assert !context.getJavaVersion().java13OrEarlier(); + Thread.interrupted(); + } + + /** + * Sets the interrupted field of the given thread to {@code false}. + */ + public void clearInterruptStatus(StaticObject guest) { + meta.HIDDEN_INTERRUPTED.setBoolean(guest, false, true); + } + + /** + * Implementation of {@link Thread#isAlive()}. + */ + public boolean isAlive(StaticObject guest) { + int state = meta.java_lang_Thread_threadStatus.getInt(guest); + return state != State.NEW.value && state != State.TERMINATED.value; + } + + // endregion thread control + + // region deprecated methods support + + /** + * Suspends a thread. On return, guarantees that the given thread has seen the suspend request. + */ + public void suspend(StaticObject guest) { + if (!isAlive(guest)) { + return; + } + DeprecationSupport support = getDeprecationSupport(guest, true); + assert support != null; + support.suspend(this); + } + + /** + * Resumes a thread. Does nothing if the thread was not previously suspended. + */ + public void resume(StaticObject guest) { + DeprecationSupport support = getDeprecationSupport(guest, false); + if (support == null) { + return; + } + support.resume(); + } + + /** + * Notifies a thread to throw an asynchronous guest throwable whenever possible. + */ + public void stop(StaticObject guest, StaticObject throwable) { + DeprecationSupport support = getDeprecationSupport(guest, true); + assert support != null; + support.stop(throwable); + Thread host = getHost(guest); + interrupt(guest); + if (host != null) { + host.interrupt(); + } + } + + /** + * Notifies a thread to throw a host {@link EspressoExitException} whenever possible. + */ + public void kill(StaticObject guest) { + DeprecationSupport support = getDeprecationSupport(guest, true); + support.kill(); + } + + /** + * Creates a thread for the given guest thread. This thread will be ready to be started. + */ + public Thread createJavaThread(StaticObject guest, DirectCallNode exit, DirectCallNode dispatch) { + Thread host = context.getEnv().createThread(new GuestRunnable(context, guest, exit, dispatch)); + // Link guest to host + meta.HIDDEN_HOST_THREAD.setHiddenObject(guest, host); + // Prepare host thread + host.setDaemon(meta.java_lang_Thread_daemon.getBoolean(guest)); + meta.java_lang_Thread_threadStatus.setInt(guest, State.RUNNABLE.value); + host.setPriority(meta.java_lang_Thread_priority.getInt(guest)); + if (isInterrupted(guest, false)) { + host.interrupt(); + } + String guestName = context.getThreadAccess().getThreadName(guest); + host.setName(guestName); + // Make the thread known to the context + context.registerThread(host, guest); + return host; + } + + /** + * Terminates a given thread. + *

    + * The following procedure is applied for termination: + *

      + *
    • Prevent other threads from {@linkplain #stop(StaticObject, StaticObject)} stopping} the + * given thread.
    • + *
    • Invoke guest {@code Thread.exit()}.
    • + *
    • Sets the status of this thread to {@link State#TERMINATED} and notifies other threads + * waiting on this thread's monitor.
    • + *
    • Unregisters the thread from the context.
    • + *
    + */ + public void terminate(StaticObject thread) { + terminate(thread, null); + } + + void terminate(StaticObject thread, DirectCallNode exit) { + DeprecationSupport support = getDeprecationSupport(thread, true); + support.exit(); + try { + if (exit == null) { + meta.java_lang_Thread_exit.invokeDirect(thread); + } else { + exit.call(thread); + } + } catch (EspressoException | EspressoExitException e) { + // just drop it + } + setTerminateStatusAndNotify(thread); + context.unregisterThread(thread); + } + + /** + * returns true if this thread has been stopped before starting, or if the context is in + * closing. + *

    + * If this method returns true, the thread will have been terminated. + */ + public boolean terminateIfStillborn(StaticObject guest) { + if (isStillborn(guest)) { + setTerminateStatusAndNotify(guest); + return true; + } + return false; + } + + private void setTerminateStatusAndNotify(StaticObject guest) { + guest.getLock().lock(); + try { + meta.java_lang_Thread_threadStatus.setInt(guest, State.TERMINATED.value); + // Notify waiting threads you are done working + guest.getLock().signalAll(); + } finally { + guest.getLock().unlock(); + } + } + + private boolean isStillborn(StaticObject guest) { + if (context.isClosing()) { + return true; + } + /* + * A bit of a special case. We want to make sure we observe the stillborn status + * synchronously. + */ + synchronized (guest) { + DeprecationSupport support = (DeprecationSupport) meta.HIDDEN_DEPRECATION_SUPPORT.getHiddenObject(guest, true); + if (support != null) { + return support.status != NORMAL; + } + return false; + } + } + + private DeprecationSupport getDeprecationSupport(StaticObject guest, boolean initIfNull) { + DeprecationSupport support = (DeprecationSupport) meta.HIDDEN_DEPRECATION_SUPPORT.getHiddenObject(guest); + if (initIfNull && support == null) { + synchronized (guest) { + support = (DeprecationSupport) meta.HIDDEN_DEPRECATION_SUPPORT.getHiddenObject(guest, true); + if (support == null) { + support = new DeprecationSupport(guest); + meta.HIDDEN_DEPRECATION_SUPPORT.setHiddenObject(guest, support, true); + } + } + } + return support; + } + + private static final class DeprecationSupport { + + private final StaticObject thread; + + private volatile StaticObject throwable = null; + /* + * Non-volatile for general performance purposes. The cost is that the target thread might + * take longer to observe requests.; + */ + private KillStatus status = NORMAL; + private SuspendLock suspendLock = null; + + DeprecationSupport(StaticObject thread) { + this.thread = thread; + } + + void suspend(ThreadsAccess threads) { + SuspendLock lock = this.suspendLock; + if (lock == null) { + synchronized (this) { + lock = new SuspendLock(threads, thread); + this.suspendLock = lock; + } + } + lock.suspend(); + } + + void resume() { + SuspendLock lock = this.suspendLock; + if (lock == null) { + return; + } + lock.resume(); + } + + synchronized void stop(StaticObject death) { + KillStatus s = status; + if (s == NORMAL || s == STOP) { + // Writing the throwable must be done before the kill status can be observed + throwable = death; + updateKillState(STOP); + } + } + + synchronized void kill() { + updateKillState(KILL); + } + + synchronized void exit() { + updateKillState(EXITING); + } + + private void updateKillState(KillStatus state) { + assert Thread.holdsLock(this); + status = state; + } + + @TruffleBoundary + void handleSuspend() { + SuspendLock lock = this.suspendLock; + if (lock == null) { + return; + } + lock.selfSuspend(); + } + + @TruffleBoundary + void handleStop(Meta meta) { + switch (status) { + case NORMAL: + case EXITING: + return; + case STOP: + synchronized (this) { + // synchronize to make sure we are still stopped. + KillStatus s = status; + if (s == STOP) { + updateKillState(NORMAL); + // check if death cause throwable is set, if not throw ThreadDeath + StaticObject deathThrowable = throwable; + throw deathThrowable != null ? meta.throwException(deathThrowable) : meta.throwException(meta.java_lang_ThreadDeath); + } else if (s == KILL) { + throw new EspressoExitException(meta.getContext().getExitStatus()); + } + // Stop status has been cleared somewhere else. + assert s == NORMAL || s == EXITING; + return; + } + case KILL: + // This thread refuses to stop. Send a host exception. + throw new EspressoExitException(meta.getContext().getExitStatus()); + } + throw EspressoError.shouldNotReachHere(); + } + } + + // region deprecated methods support +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/InterpreterToVM.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/InterpreterToVM.java index d4a9904b9c71..691de20467d2 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/InterpreterToVM.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/InterpreterToVM.java @@ -60,6 +60,7 @@ import com.oracle.truffle.espresso.substitutions.JavaType; import com.oracle.truffle.espresso.substitutions.Target_java_lang_Thread; import com.oracle.truffle.espresso.substitutions.Throws; +import com.oracle.truffle.espresso.threads.State; public final class InterpreterToVM implements ContextAccess { @@ -399,7 +400,7 @@ public static void monitorEnter(@JavaType(Object.class) StaticObject obj, Meta m EspressoContext context = meta.getContext(); if (!monitorTryLock(lock)) { StaticObject thread = context.getCurrentThread(); - Target_java_lang_Thread.fromRunnable(thread, meta, Target_java_lang_Thread.State.BLOCKED); + meta.getThreadAccess().fromRunnable(thread, State.BLOCKED); if (context.EnableManagement) { // Locks bookkeeping. meta.HIDDEN_THREAD_BLOCKED_OBJECT.setHiddenObject(thread, obj); @@ -417,7 +418,7 @@ public static void monitorEnter(@JavaType(Object.class) StaticObject obj, Meta m if (context.EnableManagement) { meta.HIDDEN_THREAD_BLOCKED_OBJECT.setHiddenObject(thread, null); } - Target_java_lang_Thread.toRunnable(thread, meta, Target_java_lang_Thread.State.RUNNABLE); + meta.getThreadAccess().toRunnable(thread); } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/Management.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/Management.java index 2912967b66e0..6e0ad894a56d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/Management.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/Management.java @@ -60,6 +60,7 @@ import com.oracle.truffle.espresso.substitutions.JavaType; import com.oracle.truffle.espresso.substitutions.SubstitutionProfiler; import com.oracle.truffle.espresso.substitutions.Target_java_lang_Thread; +import com.oracle.truffle.espresso.threads.State; @GenerateNativeEnv(target = ManagementImpl.class, prependEnv = true) public final class Management extends NativeEnv { @@ -297,7 +298,7 @@ public int GetThreadInfo(@JavaType(long[].class) StaticObject ids, int maxDepth, StaticObject thread = StaticObject.NULL; for (int j = 0; j < activeThreads.length; ++j) { - if (Target_java_lang_Thread.getThreadId(meta, activeThreads[j]) == id) { + if (getThreadAccess().getThreadId(activeThreads[j]) == id) { thread = activeThreads[j]; break; } @@ -310,7 +311,7 @@ public int GetThreadInfo(@JavaType(long[].class) StaticObject ids, int maxDepth, int threadStatus = meta.java_lang_Thread_threadStatus.getInt(thread); StaticObject lockObj = StaticObject.NULL; StaticObject lockOwner = StaticObject.NULL; - int mask = Target_java_lang_Thread.State.BLOCKED.value | Target_java_lang_Thread.State.WAITING.value | Target_java_lang_Thread.State.TIMED_WAITING.value; + int mask = State.BLOCKED.value | State.WAITING.value | State.TIMED_WAITING.value; if ((threadStatus & mask) != 0) { lockObj = (StaticObject) meta.HIDDEN_THREAD_BLOCKED_OBJECT.getHiddenObject(thread); if (lockObj == null) { @@ -567,7 +568,7 @@ public int GetVMGlobals(@JavaType(Object[].class) StaticObject names, /* jmmVMGl StaticObject[] activeThreads = getContext().getActiveThreads(); threadIds = InterpreterToVM.allocatePrimitiveArray((byte) JavaKind.Long.getBasicType(), activeThreads.length, getMeta()); for (int j = 0; j < activeThreads.length; ++j) { - long tid = Target_java_lang_Thread.getThreadId(getMeta(), activeThreads[j]); + long tid = getThreadAccess().getThreadId(activeThreads[j]); getInterpreterToVM().setArrayLong(tid, j, threadIds); } } @@ -586,7 +587,7 @@ public long GetOneThreadAllocatedMemory( StaticObject thread = StaticObject.NULL; for (int j = 0; j < activeThreads.length; ++j) { - if (Target_java_lang_Thread.getThreadId(getMeta(), activeThreads[j]) == threadId) { + if (getThreadAccess().getThreadId(activeThreads[j]) == threadId) { thread = activeThreads[j]; break; } @@ -620,7 +621,7 @@ public void GetThreadAllocatedMemory( StaticObject thread = StaticObject.NULL; for (int j = 0; j < activeThreads.length; ++j) { - if (Target_java_lang_Thread.getThreadId(meta, activeThreads[j]) == id) { + if (getThreadAccess().getThreadId(activeThreads[j]) == id) { thread = activeThreads[j]; break; } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java index 8879610cd08b..2c692a7b6e3a 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java @@ -128,6 +128,7 @@ import com.oracle.truffle.espresso.nodes.EspressoRootNode; import com.oracle.truffle.espresso.nodes.interop.ToEspressoNode; import com.oracle.truffle.espresso.nodes.interop.ToEspressoNodeGen; +import com.oracle.truffle.espresso.overlay.ReferenceSupport; import com.oracle.truffle.espresso.runtime.Attribute; import com.oracle.truffle.espresso.runtime.Classpath; import com.oracle.truffle.espresso.runtime.EspressoContext; @@ -138,14 +139,15 @@ import com.oracle.truffle.espresso.runtime.MethodHandleIntrinsics; import com.oracle.truffle.espresso.runtime.StaticObject; import com.oracle.truffle.espresso.substitutions.CallableFromNative; +import com.oracle.truffle.espresso.substitutions.EspressoReference; import com.oracle.truffle.espresso.substitutions.GenerateNativeEnv; import com.oracle.truffle.espresso.substitutions.Inject; import com.oracle.truffle.espresso.substitutions.JavaType; import com.oracle.truffle.espresso.substitutions.SubstitutionProfiler; import com.oracle.truffle.espresso.substitutions.Target_java_lang_System; import com.oracle.truffle.espresso.substitutions.Target_java_lang_Thread; -import com.oracle.truffle.espresso.substitutions.Target_java_lang_Thread.State; import com.oracle.truffle.espresso.substitutions.Target_java_lang_ref_Reference; +import com.oracle.truffle.espresso.threads.State; import com.oracle.truffle.espresso.vm.structs.JavaVMAttachArgs; import com.oracle.truffle.espresso.vm.structs.JdkVersionInfo; import com.oracle.truffle.espresso.vm.structs.Structs; @@ -798,7 +800,7 @@ public void JVM_MonitorWait(@JavaType(Object.class) StaticObject self, long time EspressoContext context = getContext(); StaticObject currentThread = context.getCurrentThread(); try { - Target_java_lang_Thread.fromRunnable(currentThread, meta, (timeout > 0 ? State.TIMED_WAITING : State.WAITING)); + meta.getThreadAccess().fromRunnable(currentThread, (timeout > 0 ? State.TIMED_WAITING : State.WAITING)); if (context.EnableManagement) { // Locks bookkeeping. meta.HIDDEN_THREAD_BLOCKED_OBJECT.setHiddenObject(currentThread, self); @@ -814,7 +816,7 @@ public void JVM_MonitorWait(@JavaType(Object.class) StaticObject self, long time } } catch (InterruptedException e) { profiler.profile(0); - Target_java_lang_Thread.setInterrupt(currentThread, false); + getThreadAccess().clearInterruptStatus(currentThread); throw meta.throwExceptionWithMessage(meta.java_lang_InterruptedException, e.getMessage()); } catch (IllegalMonitorStateException e) { profiler.profile(1); @@ -826,7 +828,7 @@ public void JVM_MonitorWait(@JavaType(Object.class) StaticObject self, long time if (context.EnableManagement) { meta.HIDDEN_THREAD_BLOCKED_OBJECT.setHiddenObject(currentThread, null); } - Target_java_lang_Thread.toRunnable(currentThread, meta, State.RUNNABLE); + meta.getThreadAccess().toRunnable(currentThread); } } @@ -1517,8 +1519,7 @@ public int DetachCurrentThread(@Inject EspressoContext context) { return JNI_OK; } getLogger().fine(() -> { - Meta meta = getMeta(); - String guestName = Target_java_lang_Thread.getThreadName(meta, currentThread); + String guestName = getThreadAccess().getThreadName(currentThread); return "DetachCurrentThread: " + guestName; }); // HotSpot will wait forever if the current VM this thread was attached to has exited @@ -1538,8 +1539,7 @@ public Method visitFrame(FrameInstance frameInstance) { if (lastJavaMethod != null) { // this thread is executing getLogger().warning(() -> { - Meta meta = getMeta(); - String guestName = Target_java_lang_Thread.getThreadName(meta, currentThread); + String guestName = getThreadAccess().getThreadName(currentThread); return "DetachCurrentThread called while thread is still executing Java code (" + guestName + ")"; }); return JNI_ERR; @@ -1553,12 +1553,12 @@ public Method visitFrame(FrameInstance frameInstance) { meta.java_lang_Thread_dispatchUncaughtException.invokeDirect(currentThread, pendingException); } - Target_java_lang_Thread.terminate(currentThread, meta); + getThreadAccess().terminate(currentThread); } catch (EspressoException e) { try { StaticObject ex = e.getExceptionObject(); String exception = ex.getKlass().getExternalName(); - String threadName = Target_java_lang_Thread.getThreadName(meta, currentThread); + String threadName = getThreadAccess().getThreadName(currentThread); context.getLogger().warning(String.format("Exception: %s thrown while terminating thread \"%s\"", exception, threadName)); Method printStackTrace = ex.getKlass().lookupMethod(Name.printStackTrace, Signature._void); printStackTrace.invokeDirect(ex); @@ -1970,7 +1970,18 @@ private Symbol namePtrToInternal(TruffleObject namePtr) { if (Types.isPrimitive(type)) { result = null; } else { - result = meta.resolveSymbolOrNull(type, loader, JVM_GetProtectionDomain(caller)); + StaticObject protectionDomain; + // If loader is null, shouldn't call ClassLoader.checkPackageAccess; otherwise get + // NPE. Put it in another way, the bootstrap class loader has all permission and + // thus no checkPackageAccess equivalence in the VM class loader. + // The caller is also passed as NULL by the java code if there is no security + // manager to avoid the performance cost of getting the calling class. + if (!StaticObject.isNull(caller) && !StaticObject.isNull(loader)) { + protectionDomain = JVM_GetProtectionDomain(caller); + } else { + protectionDomain = StaticObject.NULL; + } + result = meta.resolveSymbolOrNull(type, loader, protectionDomain); } if (result == null) { throw meta.throwExceptionWithMessage(meta.java_lang_ClassNotFoundException, NativeUtils.interopPointerToString(namePtr)); @@ -2324,9 +2335,9 @@ public int JVM_GetArrayLength(@JavaType(Object.class) StaticObject array, @Injec StaticObject instance = meta.java_lang_AssertionStatusDirectives.allocateInstance(); meta.java_lang_AssertionStatusDirectives.lookupMethod(Name._init_, Signature._void).invokeDirect(instance); meta.java_lang_AssertionStatusDirectives_classes.set(instance, meta.java_lang_String.allocateReferenceArray(0)); - meta.java_lang_AssertionStatusDirectives_classEnabled.set(instance, meta._boolean.allocateReferenceArray(0)); + meta.java_lang_AssertionStatusDirectives_classEnabled.set(instance, meta._boolean.allocatePrimitiveArray(0)); meta.java_lang_AssertionStatusDirectives_packages.set(instance, meta.java_lang_String.allocateReferenceArray(0)); - meta.java_lang_AssertionStatusDirectives_packageEnabled.set(instance, meta._boolean.allocateReferenceArray(0)); + meta.java_lang_AssertionStatusDirectives_packageEnabled.set(instance, meta._boolean.allocatePrimitiveArray(0)); boolean ea = getContext().getEnv().getOptions().get(EspressoOptions.EnableAssertions); meta.java_lang_AssertionStatusDirectives_deflt.set(instance, ea); return instance; @@ -3432,19 +3443,21 @@ public boolean JVM_HasReferencePendingList() { return getContext().hasReferencePendingList(); } + @SuppressWarnings({"rawtypes", "unchecked"}) @VmImpl(isJni = true) - public boolean JVM_PhantomReferenceRefersTo(@JavaType(Reference.class) StaticObject ref, @SuppressWarnings("unused") @JavaType(Object.class) StaticObject object, + public boolean JVM_PhantomReferenceRefersTo(@JavaType(Reference.class) StaticObject ref, @JavaType(Object.class) StaticObject object, @Inject SubstitutionProfiler profiler) { if (StaticObject.isNull(ref)) { profiler.profile(0); getMeta().throwNullPointerException(); } - assert InterpreterToVM.instanceOf(ref, getMeta().java_lang_ref_PhantomReference) : "Cannot call Reference.get on PhantomReference"; - // At this point, we would need to call the host's PhantomReference.refersTo() method, but - // it is not available in Java 8 or 11. - return false; + EspressoReference host = (EspressoReference) getMeta().HIDDEN_HOST_REFERENCE.getHiddenObject(ref); + assert host instanceof Reference; + // Call host's refersTo. Not available in 8 or 11. + return ReferenceSupport.phantomReferenceRefersTo((Reference) host, object); } + @SuppressWarnings({"rawtypes", "unchecked"}) @VmImpl(isJni = true) public boolean JVM_ReferenceRefersTo(@JavaType(Reference.class) StaticObject ref, @JavaType(Object.class) StaticObject object, @Inject SubstitutionProfiler profiler) { @@ -3452,8 +3465,10 @@ public boolean JVM_ReferenceRefersTo(@JavaType(Reference.class) StaticObject ref profiler.profile(0); getMeta().throwNullPointerException(); } - assert !InterpreterToVM.instanceOf(ref, getMeta().java_lang_ref_PhantomReference) : "Cannot call Reference.get on PhantomReference"; - return Target_java_lang_ref_Reference.get(ref, getMeta()) == object; + EspressoReference host = (EspressoReference) getMeta().HIDDEN_HOST_REFERENCE.getHiddenObject(ref); + assert host instanceof Reference; + // Call host's refersTo. Not available in 8 or 11. + return ReferenceSupport.referenceRefersTo((Reference) host, object); } @VmImpl(isJni = true) diff --git a/espresso/src/com.oracle.truffle.espresso/src/java/lang/ref/PublicFinalReference.java b/espresso/src/com.oracle.truffle.espresso/src/java/lang/ref/PublicFinalReference.java index ad4effcc2b7b..75390ee05799 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/java/lang/ref/PublicFinalReference.java +++ b/espresso/src/com.oracle.truffle.espresso/src/java/lang/ref/PublicFinalReference.java @@ -27,8 +27,7 @@ /** * Open {@link FinalReference}; implementation detail for a meta-circular implementation of - * {@link Object#finalize() finalization}. If the host supports FinalReference(s), so does the - * guest. + * finalization. If the host supports FinalReference(s), so does the guest. * *

    * This class is just a placeholder, not usable as-is. A modified version without the throwing diff --git a/graal-common.json b/graal-common.json index 13410b510ccd..2518229f5e88 100644 --- a/graal-common.json +++ b/graal-common.json @@ -1,7 +1,7 @@ { "README": "This file contains definitions that are useful for the hocon and jsonnet CI files of the graal and graal-enterprise repositories.", "ci": { - "overlay": "b6feed939cb56920c218bad4cd64e2f475eaacf1" + "overlay": "0799e09509ab1a429b63ba5ff0366fe682d04153" }, "mx_version" : "HEAD" } diff --git a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py index bd89ba573067..db90964f0fb0 100644 --- a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py +++ b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py @@ -571,6 +571,9 @@ def daCapoIterations(self): def daCapoSizes(self): raise NotImplementedError() + def completeBenchmarkList(self, bmSuiteArgs): + return sorted([bench for bench in self.daCapoIterations().keys() if self.workloadSize() in self.daCapoSizes().get(bench, [])]) + def existingSizes(self): return list(dict.fromkeys([s for bench, sizes in self.daCapoSizes().items() for s in sizes])) @@ -800,12 +803,27 @@ def run(self, benchmarks, bmSuiteArgs): "pmd": ["default", "small", "large"], "sunflow": ["default", "small", "large"], "tomcat": ["default", "small", "large", "huge"], - "tradebeans": ["default", "small", "large", "huge"], + "tradebeans": ["small", "large", "huge"], "tradesoap": ["default", "small", "large", "huge"], "xalan": ["default", "small", "large"] } +def _is_batik_supported(jdk): + """ + Determines if Batik runs on the given jdk. Batik's JPEGRegistryEntry contains a reference + to TruncatedFileException, which is specific to the Sun/Oracle JDK. On a different JDK, + this results in a NoClassDefFoundError: com/sun/image/codec/jpeg/TruncatedFileException + """ + import subprocess + try: + subprocess.check_output([jdk.javap, 'com.sun.image.codec.jpeg.TruncatedFileException']) + return True + except subprocess.CalledProcessError: + mx.warn('Batik uses Sun internal class com.sun.image.codec.jpeg.TruncatedFileException which is not present in ' + jdk.home) + return False + + class DaCapoBenchmarkSuite(BaseDaCapoBenchmarkSuite): #pylint: disable=too-many-ancestors """DaCapo benchmark suite implementation.""" @@ -815,9 +833,6 @@ def name(self): else: return "dacapo-{}".format(self.workloadSize()) - def version(self): - return super(DaCapoBenchmarkSuite, self).version() - def defaultSuiteVersion(self): return "9.12-MR1-bach" @@ -856,13 +871,16 @@ def daCapoIterations(self): # Stopped working as of 8u92 on the initial release del iterations["tomcat"] - if mx.get_jdk().javaCompliance >= '9' and self.version() in ["9.12-bach", "9.12-MR1-bach"]: - if "batik" in iterations: - # batik crashes on JDK9+. This is fixed in the dacapo chopin release only + if self.version() in ["9.12-bach", "9.12-MR1-bach"]: + if mx.get_jdk().javaCompliance >= '9': + if "batik" in iterations: + # batik crashes on JDK9+. This is fixed in the dacapo chopin release only + del iterations["batik"] + if "tradesoap" in iterations: + # validation fails transiently but frequently in the first iteration in JDK9+ + del iterations["tradesoap"] + elif not _is_batik_supported(java_home_jdk()): del iterations["batik"] - if "tradesoap" in iterations: - # validation fails transiently but frequently in the first iteration in JDK9+ - del iterations["tradesoap"] if self.workloadSize() == "small": # Ensure sufficient warmup by doubling the number of default iterations for the small configuration @@ -1313,7 +1331,7 @@ def runArgs(self, bmSuiteArgs): # Skips initial check benchmark which tests for javac.jar on classpath. runArgs += ["-pja", "-Dspecjvm.run.initial.check=false"] return runArgs - + def vmArgs(self, bmSuiteArgs): vmArgs = super(SpecJvm2008BenchmarkSuite, self).vmArgs(bmSuiteArgs) if java_home_jdk().javaCompliance >= '16' and \ @@ -1838,17 +1856,43 @@ def renaissanceLibraryName(self): def renaissanceIterations(self): benchmarks = _renaissanceConfig.copy() if self.version() == "0.9.0": - del benchmarks["scala-doku"] # was introduced in 0.10.0 + # benchmark was introduced in 0.10.0 + del benchmarks["scala-doku"] + + if mx.get_jdk().javaCompliance >= '17' and self.version() in ["0.9.0", "0.10.0", "0.11.0", "0.12.0"]: + # JDK17 support for Spark benchmarks was added in 0.13.0 + # See: renaissance-benchmarks/renaissance #295 + del benchmarks["als"] + del benchmarks["chi-square"] + del benchmarks["dec-tree"] + del benchmarks["gauss-mix"] + del benchmarks["log-regression"] + del benchmarks["movie-lens"] + del benchmarks["naive-bayes"] + del benchmarks["page-rank"] + + if mx.get_arch() != "amd64" or mx.get_jdk().javaCompliance > '11': + # GR-33879 + # JNA libraries needed are currently limited to amd64: renaissance-benchmarks/renaissance #153 + del benchmarks["db-shootout"] + + if self.version() in ["0.9.0", "0.10.0", "0.11.0"]: + if mx.get_jdk().javaCompliance > '11': + del benchmarks["neo4j-analytics"] + else: + if mx.get_jdk().javaCompliance < '11' or mx.get_jdk().javaCompliance > '15': + del benchmarks["neo4j-analytics"] return benchmarks - def version(self): - return super(RenaissanceBenchmarkSuite, self).version() + def completeBenchmarkList(self, bmSuiteArgs): + return sorted([bench for bench in _renaissanceConfig.keys()]) def defaultSuiteVersion(self): - return "0.11.0" + # return self.availableSuiteVersions()[-1] + return "0.11.0" # stick to 0.11.0 for both JIT and AOT until Native Image is compatible with 0.13.0 (GR-34147) def availableSuiteVersions(self): - return ["0.9.0", "0.10.0", "0.11.0"] + return ["0.9.0", "0.10.0", "0.11.0", "0.12.0", "0.13.0"] def renaissancePath(self): lib = mx.library(self.renaissanceLibraryName()) @@ -1884,7 +1928,7 @@ def createCommandLineArgs(self, benchmarks, bmSuiteArgs): return (self.vmArgs(bmSuiteArgs) + ["-jar", self.renaissancePath()] + runArgs + [benchArg]) def benchmarkList(self, bmSuiteArgs): - return sorted(_renaissanceConfig.keys()) + return [b for b, it in self.renaissanceIterations().items() if it != -1] def successPatterns(self): return [] diff --git a/java-benchmarks/mx.java-benchmarks/suite.py b/java-benchmarks/mx.java-benchmarks/suite.py index 5a6d8bfad05b..3cd82714bd1e 100644 --- a/java-benchmarks/mx.java-benchmarks/suite.py +++ b/java-benchmarks/mx.java-benchmarks/suite.py @@ -77,6 +77,16 @@ "sha1" : "613f7615179ea364116cdd68aa41ad44a9cc49e4", }, + "RENAISSANCE_0.12.0" : { + "urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/renaissance/renaissance-gpl-0.12.0.jar"], + "sha1" : "5bf404f875622a714f9b5c772b52ad857b97658d", + }, + + "RENAISSANCE_0.13.0" : { + "urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/renaissance/renaissance-gpl-0.13.0.jar"], + "sha1" : "65eaca6ec6ba4c7293b82644bbdefd5cb2178825", + }, + "UBENCH_AGENT_DIST" : { "urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/java-ubench-agent-2e5becaf97afcf64fd8aef3ac84fc05a3157bff5.zip"], "sha1" : "19087a34b80be8845e9a3e7f927ceb592de83762", diff --git a/regex/CHANGELOG.md b/regex/CHANGELOG.md index 51d1dc05d849..9a59d3b48c43 100644 --- a/regex/CHANGELOG.md +++ b/regex/CHANGELOG.md @@ -2,6 +2,11 @@ This changelog summarizes major changes between TRegex versions relevant to language implementors integrating TRegex into their language. This document will focus on API changes relevant to integrators of TRegex. +## Version 22.0.0 + +* Added new `ASCII` encoding that callers can use when compiling a regex to limit the range of code point matches to [0x00, 0x7f]. +* Updated Unicode data (case-folding, character properties) to version 14 of the Unicode standard. + ## Version 21.3.0 * Support for case-insensitive matching in Ruby regular expressions. diff --git a/regex/ci.hocon b/regex/ci.hocon deleted file mode 100644 index c6c9cb80c6d0..000000000000 --- a/regex/ci.hocon +++ /dev/null @@ -1,28 +0,0 @@ -regexCommon: { - setup : [ - [cd, "./regex"] - ] - timelimit : "30:00" -} - -gateLite : ${regexCommon} { - run : [ - ["mx", "build" ], - ["mx", "unittest", "--verbose", "com.oracle.truffle.regex" ] - ] -} - -regexWeekly: ${regex-weekly-notifications} { - targets: [ weekly ] -} - -builds += [ - ${linux-amd64} ${oraclejdk8} ${regexCommon} ${eclipse} ${jdt} {run : [["mx", "--strict-compliance", "gate", "--strict-mode"]], targets : [gate], name: "gate-regex-8"}, - ${linux-amd64} ${oraclejdk11} ${regexCommon} ${eclipse} {run : [["mx", "--strict-compliance", "gate", "--strict-mode"]], targets : [gate], name: "gate-regex-oraclejdk-11"}, - ${darwin-amd64} ${oraclejdk8} ${gateLite} ${regexWeekly} { - name: "gate-regex-mac-lite-8" - } - ${darwin-amd64} ${oraclejdk11} ${gateLite} ${regexWeekly} { - name: "gate-regex-mac-lite-oraclejdk-11" - } -] diff --git a/regex/ci.jsonnet b/regex/ci.jsonnet new file mode 100644 index 000000000000..883fdea288b2 --- /dev/null +++ b/regex/ci.jsonnet @@ -0,0 +1,36 @@ +{ + local common = import '../common.jsonnet', + + local regex_common = { + setup+: [ + ["cd", "./regex"], + ], + timelimit: "30:00", + }, + + local regex_gate = regex_common + common.eclipse + common.jdt + { + name: 'gate-regex-oraclejdk' + self.jdk_version, + run: [["mx", "--strict-compliance", "gate", "--strict-mode"]], + targets: ["gate"], + }, + + local regex_gate_lite = regex_common + { + name: 'gate-regex-mac-lite-oraclejdk' + self.jdk_version, + run: [ + ["mx", "build"], + ["mx", "unittest", "--verbose", "com.oracle.truffle.regex"], + ], + notify_groups:: ["regex"], + targets: ["weekly"], + }, + + builds: std.flattenArrays([ + [ + common["linux-amd64"] + jdk + regex_gate, + common["darwin-amd64"] + jdk + regex_gate_lite, + ] for jdk in [ + common.oraclejdk11, + common.oraclejdk17, + ] + ]), +} \ No newline at end of file diff --git a/regex/mx.regex/suite.py b/regex/mx.regex/suite.py index 35df7f695662..7b1cfb295a93 100644 --- a/regex/mx.regex/suite.py +++ b/regex/mx.regex/suite.py @@ -43,7 +43,7 @@ "name" : "regex", - "version" : "21.3.0", + "version" : "22.0.0", "release" : False, "groupId" : "org.graalvm.regex", "url" : "http://www.graalvm.org/", diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexLanguage.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexLanguage.java index d44c86e330e0..e58ca41393a5 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexLanguage.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexLanguage.java @@ -43,7 +43,6 @@ import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.exception.AbstractTruffleException; import com.oracle.truffle.api.instrumentation.ProvidedTags; @@ -147,7 +146,7 @@ public GroupBoundaries[] getCachedGroupBoundaries() { @Override protected CallTarget parse(ParsingRequest parsingRequest) { - return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(createRegexObject(createRegexSource(parsingRequest.getSource())))); + return RootNode.createConstantNode(createRegexObject(createRegexSource(parsingRequest.getSource()))).getCallTarget(); } private static RegexSource createRegexSource(Source source) { diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexObject.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexObject.java index 8bd0171d0682..2355339ac7f0 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexObject.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexObject.java @@ -45,7 +45,6 @@ import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.GenerateUncached; @@ -136,7 +135,7 @@ public RegexObject(RegexExecNode execNode, RegexSource source, AbstractRegexObje this.flags = flags; this.numberOfCaptureGroups = numberOfCaptureGroups; this.namedCaptureGroups = namedCaptureGroups != null ? createNamedCaptureGroupMap(namedCaptureGroups) : TruffleNull.INSTANCE; - this.execCallTarget = Truffle.getRuntime().createCallTarget(new RegexRootNode(execNode.getRegexLanguage(), execNode)); + this.execCallTarget = new RegexRootNode(execNode.getRegexLanguage(), execNode).getCallTarget(); this.backtracking = execNode.isBacktracking(); } diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexOptions.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexOptions.java index 87ce806df420..d573684d77e7 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexOptions.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexOptions.java @@ -397,6 +397,9 @@ private int parseEncoding(int i) throws RegexSyntaxException { throw optionsSyntaxErrorUnexpectedValue(iVal, Encodings.ALL_NAMES); } switch (src.charAt(iVal)) { + case 'A': + encoding = Encodings.ASCII; + return expectValue(iVal, Encodings.ASCII.getName(), Encodings.ALL_NAMES); case 'B': encoding = Encodings.LATIN_1; return expectValue(iVal, "BYTES", Encodings.ALL_NAMES); diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/charset/UnicodeGeneralCategories.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/charset/UnicodeGeneralCategories.java index 07e0ecfedea2..543aba39e64a 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/charset/UnicodeGeneralCategories.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/charset/UnicodeGeneralCategories.java @@ -62,52 +62,53 @@ static CodePointSet getGeneralCategory(String name) { 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f7d, 0x001f80, 0x001fb4, 0x001fb6, 0x001fbc, 0x001fbe, 0x001fbe, 0x001fc2, 0x001fc4, 0x001fc6, 0x001fcc, 0x001fd0, 0x001fd3, 0x001fd6, 0x001fdb, 0x001fe0, 0x001fec, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ffc, 0x002102, 0x002102, 0x002107, 0x002107, 0x00210a, 0x002113, 0x002115, 0x002115, 0x002119, 0x00211d, 0x002124, 0x002124, 0x002126, 0x002126, 0x002128, 0x002128, 0x00212a, 0x00212d, 0x00212f, 0x002134, 0x002139, 0x002139, 0x00213c, 0x00213f, - 0x002145, 0x002149, 0x00214e, 0x00214e, 0x002183, 0x002184, 0x002c00, 0x002c2e, 0x002c30, 0x002c5e, 0x002c60, 0x002c7b, 0x002c7e, 0x002ce4, 0x002ceb, 0x002cee, 0x002cf2, - 0x002cf3, 0x002d00, 0x002d25, 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, 0x00a640, 0x00a66d, 0x00a680, 0x00a69b, 0x00a722, 0x00a76f, 0x00a771, 0x00a787, 0x00a78b, 0x00a78e, - 0x00a790, 0x00a7bf, 0x00a7c2, 0x00a7ca, 0x00a7f5, 0x00a7f6, 0x00a7fa, 0x00a7fa, 0x00ab30, 0x00ab5a, 0x00ab60, 0x00ab68, 0x00ab70, 0x00abbf, 0x00fb00, 0x00fb06, 0x00fb13, - 0x00fb17, 0x00ff21, 0x00ff3a, 0x00ff41, 0x00ff5a, 0x010400, 0x01044f, 0x0104b0, 0x0104d3, 0x0104d8, 0x0104fb, 0x010c80, 0x010cb2, 0x010cc0, 0x010cf2, 0x0118a0, 0x0118df, - 0x016e40, 0x016e7f, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, - 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, - 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d6c0, 0x01d6c2, 0x01d6da, 0x01d6dc, 0x01d6fa, 0x01d6fc, 0x01d714, 0x01d716, 0x01d734, 0x01d736, - 0x01d74e, 0x01d750, 0x01d76e, 0x01d770, 0x01d788, 0x01d78a, 0x01d7a8, 0x01d7aa, 0x01d7c2, 0x01d7c4, 0x01d7cb, 0x01e900, 0x01e943)); + 0x002145, 0x002149, 0x00214e, 0x00214e, 0x002183, 0x002184, 0x002c00, 0x002c7b, 0x002c7e, 0x002ce4, 0x002ceb, 0x002cee, 0x002cf2, 0x002cf3, 0x002d00, 0x002d25, 0x002d27, + 0x002d27, 0x002d2d, 0x002d2d, 0x00a640, 0x00a66d, 0x00a680, 0x00a69b, 0x00a722, 0x00a76f, 0x00a771, 0x00a787, 0x00a78b, 0x00a78e, 0x00a790, 0x00a7ca, 0x00a7d0, 0x00a7d1, + 0x00a7d3, 0x00a7d3, 0x00a7d5, 0x00a7d9, 0x00a7f5, 0x00a7f6, 0x00a7fa, 0x00a7fa, 0x00ab30, 0x00ab5a, 0x00ab60, 0x00ab68, 0x00ab70, 0x00abbf, 0x00fb00, 0x00fb06, 0x00fb13, + 0x00fb17, 0x00ff21, 0x00ff3a, 0x00ff41, 0x00ff5a, 0x010400, 0x01044f, 0x0104b0, 0x0104d3, 0x0104d8, 0x0104fb, 0x010570, 0x01057a, 0x01057c, 0x01058a, 0x01058c, 0x010592, + 0x010594, 0x010595, 0x010597, 0x0105a1, 0x0105a3, 0x0105b1, 0x0105b3, 0x0105b9, 0x0105bb, 0x0105bc, 0x010c80, 0x010cb2, 0x010cc0, 0x010cf2, 0x0118a0, 0x0118df, 0x016e40, + 0x016e7f, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, 0x01d4bb, + 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, + 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d6c0, 0x01d6c2, 0x01d6da, 0x01d6dc, 0x01d6fa, 0x01d6fc, 0x01d714, 0x01d716, 0x01d734, 0x01d736, 0x01d74e, + 0x01d750, 0x01d76e, 0x01d770, 0x01d788, 0x01d78a, 0x01d7a8, 0x01d7aa, 0x01d7c2, 0x01d7c4, 0x01d7cb, 0x01df00, 0x01df09, 0x01df0b, 0x01df1e, 0x01e900, 0x01e943)); GENERAL_CATEGORIES.put("gc=L", CodePointSet.createNoDedup(0x000041, 0x00005a, 0x000061, 0x00007a, 0x0000aa, 0x0000aa, 0x0000b5, 0x0000b5, 0x0000ba, 0x0000ba, 0x0000c0, 0x0000d6, 0x0000d8, 0x0000f6, 0x0000f8, 0x0002c1, 0x0002c6, 0x0002d1, 0x0002e0, 0x0002e4, 0x0002ec, 0x0002ec, 0x0002ee, 0x0002ee, 0x000370, 0x000374, 0x000376, 0x000377, 0x00037a, 0x00037d, 0x00037f, 0x00037f, 0x000386, 0x000386, 0x000388, 0x00038a, 0x00038c, 0x00038c, 0x00038e, 0x0003a1, 0x0003a3, 0x0003f5, 0x0003f7, 0x000481, 0x00048a, 0x00052f, 0x000531, 0x000556, 0x000559, 0x000559, 0x000560, 0x000588, 0x0005d0, 0x0005ea, 0x0005ef, 0x0005f2, 0x000620, 0x00064a, 0x00066e, 0x00066f, 0x000671, 0x0006d3, 0x0006d5, 0x0006d5, 0x0006e5, 0x0006e6, 0x0006ee, 0x0006ef, 0x0006fa, 0x0006fc, 0x0006ff, 0x0006ff, 0x000710, 0x000710, 0x000712, 0x00072f, 0x00074d, 0x0007a5, 0x0007b1, 0x0007b1, 0x0007ca, 0x0007ea, 0x0007f4, 0x0007f5, 0x0007fa, 0x0007fa, 0x000800, 0x000815, 0x00081a, 0x00081a, 0x000824, 0x000824, 0x000828, 0x000828, 0x000840, 0x000858, 0x000860, 0x00086a, - 0x0008a0, 0x0008b4, 0x0008b6, 0x0008c7, 0x000904, 0x000939, 0x00093d, 0x00093d, 0x000950, 0x000950, 0x000958, 0x000961, 0x000971, 0x000980, 0x000985, 0x00098c, 0x00098f, - 0x000990, 0x000993, 0x0009a8, 0x0009aa, 0x0009b0, 0x0009b2, 0x0009b2, 0x0009b6, 0x0009b9, 0x0009bd, 0x0009bd, 0x0009ce, 0x0009ce, 0x0009dc, 0x0009dd, 0x0009df, 0x0009e1, - 0x0009f0, 0x0009f1, 0x0009fc, 0x0009fc, 0x000a05, 0x000a0a, 0x000a0f, 0x000a10, 0x000a13, 0x000a28, 0x000a2a, 0x000a30, 0x000a32, 0x000a33, 0x000a35, 0x000a36, 0x000a38, - 0x000a39, 0x000a59, 0x000a5c, 0x000a5e, 0x000a5e, 0x000a72, 0x000a74, 0x000a85, 0x000a8d, 0x000a8f, 0x000a91, 0x000a93, 0x000aa8, 0x000aaa, 0x000ab0, 0x000ab2, 0x000ab3, - 0x000ab5, 0x000ab9, 0x000abd, 0x000abd, 0x000ad0, 0x000ad0, 0x000ae0, 0x000ae1, 0x000af9, 0x000af9, 0x000b05, 0x000b0c, 0x000b0f, 0x000b10, 0x000b13, 0x000b28, 0x000b2a, - 0x000b30, 0x000b32, 0x000b33, 0x000b35, 0x000b39, 0x000b3d, 0x000b3d, 0x000b5c, 0x000b5d, 0x000b5f, 0x000b61, 0x000b71, 0x000b71, 0x000b83, 0x000b83, 0x000b85, 0x000b8a, - 0x000b8e, 0x000b90, 0x000b92, 0x000b95, 0x000b99, 0x000b9a, 0x000b9c, 0x000b9c, 0x000b9e, 0x000b9f, 0x000ba3, 0x000ba4, 0x000ba8, 0x000baa, 0x000bae, 0x000bb9, 0x000bd0, - 0x000bd0, 0x000c05, 0x000c0c, 0x000c0e, 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3d, 0x000c3d, 0x000c58, 0x000c5a, 0x000c60, 0x000c61, 0x000c80, 0x000c80, - 0x000c85, 0x000c8c, 0x000c8e, 0x000c90, 0x000c92, 0x000ca8, 0x000caa, 0x000cb3, 0x000cb5, 0x000cb9, 0x000cbd, 0x000cbd, 0x000cde, 0x000cde, 0x000ce0, 0x000ce1, 0x000cf1, - 0x000cf2, 0x000d04, 0x000d0c, 0x000d0e, 0x000d10, 0x000d12, 0x000d3a, 0x000d3d, 0x000d3d, 0x000d4e, 0x000d4e, 0x000d54, 0x000d56, 0x000d5f, 0x000d61, 0x000d7a, 0x000d7f, - 0x000d85, 0x000d96, 0x000d9a, 0x000db1, 0x000db3, 0x000dbb, 0x000dbd, 0x000dbd, 0x000dc0, 0x000dc6, 0x000e01, 0x000e30, 0x000e32, 0x000e33, 0x000e40, 0x000e46, 0x000e81, - 0x000e82, 0x000e84, 0x000e84, 0x000e86, 0x000e8a, 0x000e8c, 0x000ea3, 0x000ea5, 0x000ea5, 0x000ea7, 0x000eb0, 0x000eb2, 0x000eb3, 0x000ebd, 0x000ebd, 0x000ec0, 0x000ec4, - 0x000ec6, 0x000ec6, 0x000edc, 0x000edf, 0x000f00, 0x000f00, 0x000f40, 0x000f47, 0x000f49, 0x000f6c, 0x000f88, 0x000f8c, 0x001000, 0x00102a, 0x00103f, 0x00103f, 0x001050, - 0x001055, 0x00105a, 0x00105d, 0x001061, 0x001061, 0x001065, 0x001066, 0x00106e, 0x001070, 0x001075, 0x001081, 0x00108e, 0x00108e, 0x0010a0, 0x0010c5, 0x0010c7, 0x0010c7, - 0x0010cd, 0x0010cd, 0x0010d0, 0x0010fa, 0x0010fc, 0x001248, 0x00124a, 0x00124d, 0x001250, 0x001256, 0x001258, 0x001258, 0x00125a, 0x00125d, 0x001260, 0x001288, 0x00128a, - 0x00128d, 0x001290, 0x0012b0, 0x0012b2, 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, 0x0012d8, 0x001310, 0x001312, 0x001315, - 0x001318, 0x00135a, 0x001380, 0x00138f, 0x0013a0, 0x0013f5, 0x0013f8, 0x0013fd, 0x001401, 0x00166c, 0x00166f, 0x00167f, 0x001681, 0x00169a, 0x0016a0, 0x0016ea, 0x0016f1, - 0x0016f8, 0x001700, 0x00170c, 0x00170e, 0x001711, 0x001720, 0x001731, 0x001740, 0x001751, 0x001760, 0x00176c, 0x00176e, 0x001770, 0x001780, 0x0017b3, 0x0017d7, 0x0017d7, - 0x0017dc, 0x0017dc, 0x001820, 0x001878, 0x001880, 0x001884, 0x001887, 0x0018a8, 0x0018aa, 0x0018aa, 0x0018b0, 0x0018f5, 0x001900, 0x00191e, 0x001950, 0x00196d, 0x001970, - 0x001974, 0x001980, 0x0019ab, 0x0019b0, 0x0019c9, 0x001a00, 0x001a16, 0x001a20, 0x001a54, 0x001aa7, 0x001aa7, 0x001b05, 0x001b33, 0x001b45, 0x001b4b, 0x001b83, 0x001ba0, - 0x001bae, 0x001baf, 0x001bba, 0x001be5, 0x001c00, 0x001c23, 0x001c4d, 0x001c4f, 0x001c5a, 0x001c7d, 0x001c80, 0x001c88, 0x001c90, 0x001cba, 0x001cbd, 0x001cbf, 0x001ce9, - 0x001cec, 0x001cee, 0x001cf3, 0x001cf5, 0x001cf6, 0x001cfa, 0x001cfa, 0x001d00, 0x001dbf, 0x001e00, 0x001f15, 0x001f18, 0x001f1d, 0x001f20, 0x001f45, 0x001f48, 0x001f4d, - 0x001f50, 0x001f57, 0x001f59, 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f7d, 0x001f80, 0x001fb4, 0x001fb6, 0x001fbc, 0x001fbe, 0x001fbe, 0x001fc2, - 0x001fc4, 0x001fc6, 0x001fcc, 0x001fd0, 0x001fd3, 0x001fd6, 0x001fdb, 0x001fe0, 0x001fec, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ffc, 0x002071, 0x002071, 0x00207f, 0x00207f, - 0x002090, 0x00209c, 0x002102, 0x002102, 0x002107, 0x002107, 0x00210a, 0x002113, 0x002115, 0x002115, 0x002119, 0x00211d, 0x002124, 0x002124, 0x002126, 0x002126, 0x002128, - 0x002128, 0x00212a, 0x00212d, 0x00212f, 0x002139, 0x00213c, 0x00213f, 0x002145, 0x002149, 0x00214e, 0x00214e, 0x002183, 0x002184, 0x002c00, 0x002c2e, 0x002c30, 0x002c5e, - 0x002c60, 0x002ce4, 0x002ceb, 0x002cee, 0x002cf2, 0x002cf3, 0x002d00, 0x002d25, 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, 0x002d30, 0x002d67, 0x002d6f, 0x002d6f, 0x002d80, - 0x002d96, 0x002da0, 0x002da6, 0x002da8, 0x002dae, 0x002db0, 0x002db6, 0x002db8, 0x002dbe, 0x002dc0, 0x002dc6, 0x002dc8, 0x002dce, 0x002dd0, 0x002dd6, 0x002dd8, 0x002dde, - 0x002e2f, 0x002e2f, 0x003005, 0x003006, 0x003031, 0x003035, 0x00303b, 0x00303c, 0x003041, 0x003096, 0x00309d, 0x00309f, 0x0030a1, 0x0030fa, 0x0030fc, 0x0030ff, 0x003105, - 0x00312f, 0x003131, 0x00318e, 0x0031a0, 0x0031bf, 0x0031f0, 0x0031ff, 0x003400, 0x004dbf, 0x004e00, 0x009ffc, 0x00a000, 0x00a48c, 0x00a4d0, 0x00a4fd, 0x00a500, 0x00a60c, - 0x00a610, 0x00a61f, 0x00a62a, 0x00a62b, 0x00a640, 0x00a66e, 0x00a67f, 0x00a69d, 0x00a6a0, 0x00a6e5, 0x00a717, 0x00a71f, 0x00a722, 0x00a788, 0x00a78b, 0x00a7bf, 0x00a7c2, - 0x00a7ca, 0x00a7f5, 0x00a801, 0x00a803, 0x00a805, 0x00a807, 0x00a80a, 0x00a80c, 0x00a822, 0x00a840, 0x00a873, 0x00a882, 0x00a8b3, 0x00a8f2, 0x00a8f7, 0x00a8fb, 0x00a8fb, + 0x000870, 0x000887, 0x000889, 0x00088e, 0x0008a0, 0x0008c9, 0x000904, 0x000939, 0x00093d, 0x00093d, 0x000950, 0x000950, 0x000958, 0x000961, 0x000971, 0x000980, 0x000985, + 0x00098c, 0x00098f, 0x000990, 0x000993, 0x0009a8, 0x0009aa, 0x0009b0, 0x0009b2, 0x0009b2, 0x0009b6, 0x0009b9, 0x0009bd, 0x0009bd, 0x0009ce, 0x0009ce, 0x0009dc, 0x0009dd, + 0x0009df, 0x0009e1, 0x0009f0, 0x0009f1, 0x0009fc, 0x0009fc, 0x000a05, 0x000a0a, 0x000a0f, 0x000a10, 0x000a13, 0x000a28, 0x000a2a, 0x000a30, 0x000a32, 0x000a33, 0x000a35, + 0x000a36, 0x000a38, 0x000a39, 0x000a59, 0x000a5c, 0x000a5e, 0x000a5e, 0x000a72, 0x000a74, 0x000a85, 0x000a8d, 0x000a8f, 0x000a91, 0x000a93, 0x000aa8, 0x000aaa, 0x000ab0, + 0x000ab2, 0x000ab3, 0x000ab5, 0x000ab9, 0x000abd, 0x000abd, 0x000ad0, 0x000ad0, 0x000ae0, 0x000ae1, 0x000af9, 0x000af9, 0x000b05, 0x000b0c, 0x000b0f, 0x000b10, 0x000b13, + 0x000b28, 0x000b2a, 0x000b30, 0x000b32, 0x000b33, 0x000b35, 0x000b39, 0x000b3d, 0x000b3d, 0x000b5c, 0x000b5d, 0x000b5f, 0x000b61, 0x000b71, 0x000b71, 0x000b83, 0x000b83, + 0x000b85, 0x000b8a, 0x000b8e, 0x000b90, 0x000b92, 0x000b95, 0x000b99, 0x000b9a, 0x000b9c, 0x000b9c, 0x000b9e, 0x000b9f, 0x000ba3, 0x000ba4, 0x000ba8, 0x000baa, 0x000bae, + 0x000bb9, 0x000bd0, 0x000bd0, 0x000c05, 0x000c0c, 0x000c0e, 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3d, 0x000c3d, 0x000c58, 0x000c5a, 0x000c5d, 0x000c5d, + 0x000c60, 0x000c61, 0x000c80, 0x000c80, 0x000c85, 0x000c8c, 0x000c8e, 0x000c90, 0x000c92, 0x000ca8, 0x000caa, 0x000cb3, 0x000cb5, 0x000cb9, 0x000cbd, 0x000cbd, 0x000cdd, + 0x000cde, 0x000ce0, 0x000ce1, 0x000cf1, 0x000cf2, 0x000d04, 0x000d0c, 0x000d0e, 0x000d10, 0x000d12, 0x000d3a, 0x000d3d, 0x000d3d, 0x000d4e, 0x000d4e, 0x000d54, 0x000d56, + 0x000d5f, 0x000d61, 0x000d7a, 0x000d7f, 0x000d85, 0x000d96, 0x000d9a, 0x000db1, 0x000db3, 0x000dbb, 0x000dbd, 0x000dbd, 0x000dc0, 0x000dc6, 0x000e01, 0x000e30, 0x000e32, + 0x000e33, 0x000e40, 0x000e46, 0x000e81, 0x000e82, 0x000e84, 0x000e84, 0x000e86, 0x000e8a, 0x000e8c, 0x000ea3, 0x000ea5, 0x000ea5, 0x000ea7, 0x000eb0, 0x000eb2, 0x000eb3, + 0x000ebd, 0x000ebd, 0x000ec0, 0x000ec4, 0x000ec6, 0x000ec6, 0x000edc, 0x000edf, 0x000f00, 0x000f00, 0x000f40, 0x000f47, 0x000f49, 0x000f6c, 0x000f88, 0x000f8c, 0x001000, + 0x00102a, 0x00103f, 0x00103f, 0x001050, 0x001055, 0x00105a, 0x00105d, 0x001061, 0x001061, 0x001065, 0x001066, 0x00106e, 0x001070, 0x001075, 0x001081, 0x00108e, 0x00108e, + 0x0010a0, 0x0010c5, 0x0010c7, 0x0010c7, 0x0010cd, 0x0010cd, 0x0010d0, 0x0010fa, 0x0010fc, 0x001248, 0x00124a, 0x00124d, 0x001250, 0x001256, 0x001258, 0x001258, 0x00125a, + 0x00125d, 0x001260, 0x001288, 0x00128a, 0x00128d, 0x001290, 0x0012b0, 0x0012b2, 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, + 0x0012d8, 0x001310, 0x001312, 0x001315, 0x001318, 0x00135a, 0x001380, 0x00138f, 0x0013a0, 0x0013f5, 0x0013f8, 0x0013fd, 0x001401, 0x00166c, 0x00166f, 0x00167f, 0x001681, + 0x00169a, 0x0016a0, 0x0016ea, 0x0016f1, 0x0016f8, 0x001700, 0x001711, 0x00171f, 0x001731, 0x001740, 0x001751, 0x001760, 0x00176c, 0x00176e, 0x001770, 0x001780, 0x0017b3, + 0x0017d7, 0x0017d7, 0x0017dc, 0x0017dc, 0x001820, 0x001878, 0x001880, 0x001884, 0x001887, 0x0018a8, 0x0018aa, 0x0018aa, 0x0018b0, 0x0018f5, 0x001900, 0x00191e, 0x001950, + 0x00196d, 0x001970, 0x001974, 0x001980, 0x0019ab, 0x0019b0, 0x0019c9, 0x001a00, 0x001a16, 0x001a20, 0x001a54, 0x001aa7, 0x001aa7, 0x001b05, 0x001b33, 0x001b45, 0x001b4c, + 0x001b83, 0x001ba0, 0x001bae, 0x001baf, 0x001bba, 0x001be5, 0x001c00, 0x001c23, 0x001c4d, 0x001c4f, 0x001c5a, 0x001c7d, 0x001c80, 0x001c88, 0x001c90, 0x001cba, 0x001cbd, + 0x001cbf, 0x001ce9, 0x001cec, 0x001cee, 0x001cf3, 0x001cf5, 0x001cf6, 0x001cfa, 0x001cfa, 0x001d00, 0x001dbf, 0x001e00, 0x001f15, 0x001f18, 0x001f1d, 0x001f20, 0x001f45, + 0x001f48, 0x001f4d, 0x001f50, 0x001f57, 0x001f59, 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f7d, 0x001f80, 0x001fb4, 0x001fb6, 0x001fbc, 0x001fbe, + 0x001fbe, 0x001fc2, 0x001fc4, 0x001fc6, 0x001fcc, 0x001fd0, 0x001fd3, 0x001fd6, 0x001fdb, 0x001fe0, 0x001fec, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ffc, 0x002071, 0x002071, + 0x00207f, 0x00207f, 0x002090, 0x00209c, 0x002102, 0x002102, 0x002107, 0x002107, 0x00210a, 0x002113, 0x002115, 0x002115, 0x002119, 0x00211d, 0x002124, 0x002124, 0x002126, + 0x002126, 0x002128, 0x002128, 0x00212a, 0x00212d, 0x00212f, 0x002139, 0x00213c, 0x00213f, 0x002145, 0x002149, 0x00214e, 0x00214e, 0x002183, 0x002184, 0x002c00, 0x002ce4, + 0x002ceb, 0x002cee, 0x002cf2, 0x002cf3, 0x002d00, 0x002d25, 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, 0x002d30, 0x002d67, 0x002d6f, 0x002d6f, 0x002d80, 0x002d96, 0x002da0, + 0x002da6, 0x002da8, 0x002dae, 0x002db0, 0x002db6, 0x002db8, 0x002dbe, 0x002dc0, 0x002dc6, 0x002dc8, 0x002dce, 0x002dd0, 0x002dd6, 0x002dd8, 0x002dde, 0x002e2f, 0x002e2f, + 0x003005, 0x003006, 0x003031, 0x003035, 0x00303b, 0x00303c, 0x003041, 0x003096, 0x00309d, 0x00309f, 0x0030a1, 0x0030fa, 0x0030fc, 0x0030ff, 0x003105, 0x00312f, 0x003131, + 0x00318e, 0x0031a0, 0x0031bf, 0x0031f0, 0x0031ff, 0x003400, 0x004dbf, 0x004e00, 0x00a48c, 0x00a4d0, 0x00a4fd, 0x00a500, 0x00a60c, 0x00a610, 0x00a61f, 0x00a62a, 0x00a62b, + 0x00a640, 0x00a66e, 0x00a67f, 0x00a69d, 0x00a6a0, 0x00a6e5, 0x00a717, 0x00a71f, 0x00a722, 0x00a788, 0x00a78b, 0x00a7ca, 0x00a7d0, 0x00a7d1, 0x00a7d3, 0x00a7d3, 0x00a7d5, + 0x00a7d9, 0x00a7f2, 0x00a801, 0x00a803, 0x00a805, 0x00a807, 0x00a80a, 0x00a80c, 0x00a822, 0x00a840, 0x00a873, 0x00a882, 0x00a8b3, 0x00a8f2, 0x00a8f7, 0x00a8fb, 0x00a8fb, 0x00a8fd, 0x00a8fe, 0x00a90a, 0x00a925, 0x00a930, 0x00a946, 0x00a960, 0x00a97c, 0x00a984, 0x00a9b2, 0x00a9cf, 0x00a9cf, 0x00a9e0, 0x00a9e4, 0x00a9e6, 0x00a9ef, 0x00a9fa, 0x00a9fe, 0x00aa00, 0x00aa28, 0x00aa40, 0x00aa42, 0x00aa44, 0x00aa4b, 0x00aa60, 0x00aa76, 0x00aa7a, 0x00aa7a, 0x00aa7e, 0x00aaaf, 0x00aab1, 0x00aab1, 0x00aab5, 0x00aab6, 0x00aab9, 0x00aabd, 0x00aac0, 0x00aac0, 0x00aac2, 0x00aac2, 0x00aadb, 0x00aadd, 0x00aae0, 0x00aaea, 0x00aaf2, 0x00aaf4, 0x00ab01, 0x00ab06, 0x00ab09, 0x00ab0e, 0x00ab11, @@ -117,68 +118,72 @@ static CodePointSet getGeneralCategory(String name) { 0x00fe76, 0x00fefc, 0x00ff21, 0x00ff3a, 0x00ff41, 0x00ff5a, 0x00ff66, 0x00ffbe, 0x00ffc2, 0x00ffc7, 0x00ffca, 0x00ffcf, 0x00ffd2, 0x00ffd7, 0x00ffda, 0x00ffdc, 0x010000, 0x01000b, 0x01000d, 0x010026, 0x010028, 0x01003a, 0x01003c, 0x01003d, 0x01003f, 0x01004d, 0x010050, 0x01005d, 0x010080, 0x0100fa, 0x010280, 0x01029c, 0x0102a0, 0x0102d0, 0x010300, 0x01031f, 0x01032d, 0x010340, 0x010342, 0x010349, 0x010350, 0x010375, 0x010380, 0x01039d, 0x0103a0, 0x0103c3, 0x0103c8, 0x0103cf, 0x010400, 0x01049d, 0x0104b0, - 0x0104d3, 0x0104d8, 0x0104fb, 0x010500, 0x010527, 0x010530, 0x010563, 0x010600, 0x010736, 0x010740, 0x010755, 0x010760, 0x010767, 0x010800, 0x010805, 0x010808, 0x010808, - 0x01080a, 0x010835, 0x010837, 0x010838, 0x01083c, 0x01083c, 0x01083f, 0x010855, 0x010860, 0x010876, 0x010880, 0x01089e, 0x0108e0, 0x0108f2, 0x0108f4, 0x0108f5, 0x010900, - 0x010915, 0x010920, 0x010939, 0x010980, 0x0109b7, 0x0109be, 0x0109bf, 0x010a00, 0x010a00, 0x010a10, 0x010a13, 0x010a15, 0x010a17, 0x010a19, 0x010a35, 0x010a60, 0x010a7c, - 0x010a80, 0x010a9c, 0x010ac0, 0x010ac7, 0x010ac9, 0x010ae4, 0x010b00, 0x010b35, 0x010b40, 0x010b55, 0x010b60, 0x010b72, 0x010b80, 0x010b91, 0x010c00, 0x010c48, 0x010c80, - 0x010cb2, 0x010cc0, 0x010cf2, 0x010d00, 0x010d23, 0x010e80, 0x010ea9, 0x010eb0, 0x010eb1, 0x010f00, 0x010f1c, 0x010f27, 0x010f27, 0x010f30, 0x010f45, 0x010fb0, 0x010fc4, - 0x010fe0, 0x010ff6, 0x011003, 0x011037, 0x011083, 0x0110af, 0x0110d0, 0x0110e8, 0x011103, 0x011126, 0x011144, 0x011144, 0x011147, 0x011147, 0x011150, 0x011172, 0x011176, - 0x011176, 0x011183, 0x0111b2, 0x0111c1, 0x0111c4, 0x0111da, 0x0111da, 0x0111dc, 0x0111dc, 0x011200, 0x011211, 0x011213, 0x01122b, 0x011280, 0x011286, 0x011288, 0x011288, - 0x01128a, 0x01128d, 0x01128f, 0x01129d, 0x01129f, 0x0112a8, 0x0112b0, 0x0112de, 0x011305, 0x01130c, 0x01130f, 0x011310, 0x011313, 0x011328, 0x01132a, 0x011330, 0x011332, - 0x011333, 0x011335, 0x011339, 0x01133d, 0x01133d, 0x011350, 0x011350, 0x01135d, 0x011361, 0x011400, 0x011434, 0x011447, 0x01144a, 0x01145f, 0x011461, 0x011480, 0x0114af, - 0x0114c4, 0x0114c5, 0x0114c7, 0x0114c7, 0x011580, 0x0115ae, 0x0115d8, 0x0115db, 0x011600, 0x01162f, 0x011644, 0x011644, 0x011680, 0x0116aa, 0x0116b8, 0x0116b8, 0x011700, - 0x01171a, 0x011800, 0x01182b, 0x0118a0, 0x0118df, 0x0118ff, 0x011906, 0x011909, 0x011909, 0x01190c, 0x011913, 0x011915, 0x011916, 0x011918, 0x01192f, 0x01193f, 0x01193f, - 0x011941, 0x011941, 0x0119a0, 0x0119a7, 0x0119aa, 0x0119d0, 0x0119e1, 0x0119e1, 0x0119e3, 0x0119e3, 0x011a00, 0x011a00, 0x011a0b, 0x011a32, 0x011a3a, 0x011a3a, 0x011a50, - 0x011a50, 0x011a5c, 0x011a89, 0x011a9d, 0x011a9d, 0x011ac0, 0x011af8, 0x011c00, 0x011c08, 0x011c0a, 0x011c2e, 0x011c40, 0x011c40, 0x011c72, 0x011c8f, 0x011d00, 0x011d06, - 0x011d08, 0x011d09, 0x011d0b, 0x011d30, 0x011d46, 0x011d46, 0x011d60, 0x011d65, 0x011d67, 0x011d68, 0x011d6a, 0x011d89, 0x011d98, 0x011d98, 0x011ee0, 0x011ef2, 0x011fb0, - 0x011fb0, 0x012000, 0x012399, 0x012480, 0x012543, 0x013000, 0x01342e, 0x014400, 0x014646, 0x016800, 0x016a38, 0x016a40, 0x016a5e, 0x016ad0, 0x016aed, 0x016b00, 0x016b2f, + 0x0104d3, 0x0104d8, 0x0104fb, 0x010500, 0x010527, 0x010530, 0x010563, 0x010570, 0x01057a, 0x01057c, 0x01058a, 0x01058c, 0x010592, 0x010594, 0x010595, 0x010597, 0x0105a1, + 0x0105a3, 0x0105b1, 0x0105b3, 0x0105b9, 0x0105bb, 0x0105bc, 0x010600, 0x010736, 0x010740, 0x010755, 0x010760, 0x010767, 0x010780, 0x010785, 0x010787, 0x0107b0, 0x0107b2, + 0x0107ba, 0x010800, 0x010805, 0x010808, 0x010808, 0x01080a, 0x010835, 0x010837, 0x010838, 0x01083c, 0x01083c, 0x01083f, 0x010855, 0x010860, 0x010876, 0x010880, 0x01089e, + 0x0108e0, 0x0108f2, 0x0108f4, 0x0108f5, 0x010900, 0x010915, 0x010920, 0x010939, 0x010980, 0x0109b7, 0x0109be, 0x0109bf, 0x010a00, 0x010a00, 0x010a10, 0x010a13, 0x010a15, + 0x010a17, 0x010a19, 0x010a35, 0x010a60, 0x010a7c, 0x010a80, 0x010a9c, 0x010ac0, 0x010ac7, 0x010ac9, 0x010ae4, 0x010b00, 0x010b35, 0x010b40, 0x010b55, 0x010b60, 0x010b72, + 0x010b80, 0x010b91, 0x010c00, 0x010c48, 0x010c80, 0x010cb2, 0x010cc0, 0x010cf2, 0x010d00, 0x010d23, 0x010e80, 0x010ea9, 0x010eb0, 0x010eb1, 0x010f00, 0x010f1c, 0x010f27, + 0x010f27, 0x010f30, 0x010f45, 0x010f70, 0x010f81, 0x010fb0, 0x010fc4, 0x010fe0, 0x010ff6, 0x011003, 0x011037, 0x011071, 0x011072, 0x011075, 0x011075, 0x011083, 0x0110af, + 0x0110d0, 0x0110e8, 0x011103, 0x011126, 0x011144, 0x011144, 0x011147, 0x011147, 0x011150, 0x011172, 0x011176, 0x011176, 0x011183, 0x0111b2, 0x0111c1, 0x0111c4, 0x0111da, + 0x0111da, 0x0111dc, 0x0111dc, 0x011200, 0x011211, 0x011213, 0x01122b, 0x011280, 0x011286, 0x011288, 0x011288, 0x01128a, 0x01128d, 0x01128f, 0x01129d, 0x01129f, 0x0112a8, + 0x0112b0, 0x0112de, 0x011305, 0x01130c, 0x01130f, 0x011310, 0x011313, 0x011328, 0x01132a, 0x011330, 0x011332, 0x011333, 0x011335, 0x011339, 0x01133d, 0x01133d, 0x011350, + 0x011350, 0x01135d, 0x011361, 0x011400, 0x011434, 0x011447, 0x01144a, 0x01145f, 0x011461, 0x011480, 0x0114af, 0x0114c4, 0x0114c5, 0x0114c7, 0x0114c7, 0x011580, 0x0115ae, + 0x0115d8, 0x0115db, 0x011600, 0x01162f, 0x011644, 0x011644, 0x011680, 0x0116aa, 0x0116b8, 0x0116b8, 0x011700, 0x01171a, 0x011740, 0x011746, 0x011800, 0x01182b, 0x0118a0, + 0x0118df, 0x0118ff, 0x011906, 0x011909, 0x011909, 0x01190c, 0x011913, 0x011915, 0x011916, 0x011918, 0x01192f, 0x01193f, 0x01193f, 0x011941, 0x011941, 0x0119a0, 0x0119a7, + 0x0119aa, 0x0119d0, 0x0119e1, 0x0119e1, 0x0119e3, 0x0119e3, 0x011a00, 0x011a00, 0x011a0b, 0x011a32, 0x011a3a, 0x011a3a, 0x011a50, 0x011a50, 0x011a5c, 0x011a89, 0x011a9d, + 0x011a9d, 0x011ab0, 0x011af8, 0x011c00, 0x011c08, 0x011c0a, 0x011c2e, 0x011c40, 0x011c40, 0x011c72, 0x011c8f, 0x011d00, 0x011d06, 0x011d08, 0x011d09, 0x011d0b, 0x011d30, + 0x011d46, 0x011d46, 0x011d60, 0x011d65, 0x011d67, 0x011d68, 0x011d6a, 0x011d89, 0x011d98, 0x011d98, 0x011ee0, 0x011ef2, 0x011fb0, 0x011fb0, 0x012000, 0x012399, 0x012480, + 0x012543, 0x012f90, 0x012ff0, 0x013000, 0x01342e, 0x014400, 0x014646, 0x016800, 0x016a38, 0x016a40, 0x016a5e, 0x016a70, 0x016abe, 0x016ad0, 0x016aed, 0x016b00, 0x016b2f, 0x016b40, 0x016b43, 0x016b63, 0x016b77, 0x016b7d, 0x016b8f, 0x016e40, 0x016e7f, 0x016f00, 0x016f4a, 0x016f50, 0x016f50, 0x016f93, 0x016f9f, 0x016fe0, 0x016fe1, 0x016fe3, - 0x016fe3, 0x017000, 0x0187f7, 0x018800, 0x018cd5, 0x018d00, 0x018d08, 0x01b000, 0x01b11e, 0x01b150, 0x01b152, 0x01b164, 0x01b167, 0x01b170, 0x01b2fb, 0x01bc00, 0x01bc6a, - 0x01bc70, 0x01bc7c, 0x01bc80, 0x01bc88, 0x01bc90, 0x01bc99, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, - 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, - 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d6c0, 0x01d6c2, 0x01d6da, 0x01d6dc, 0x01d6fa, 0x01d6fc, - 0x01d714, 0x01d716, 0x01d734, 0x01d736, 0x01d74e, 0x01d750, 0x01d76e, 0x01d770, 0x01d788, 0x01d78a, 0x01d7a8, 0x01d7aa, 0x01d7c2, 0x01d7c4, 0x01d7cb, 0x01e100, 0x01e12c, - 0x01e137, 0x01e13d, 0x01e14e, 0x01e14e, 0x01e2c0, 0x01e2eb, 0x01e800, 0x01e8c4, 0x01e900, 0x01e943, 0x01e94b, 0x01e94b, 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, - 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, 0x01ee39, 0x01ee3b, 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, - 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, 0x01ee57, 0x01ee57, 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, - 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, 0x01ee72, 0x01ee74, 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, - 0x01ee80, 0x01ee89, 0x01ee8b, 0x01ee9b, 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, 0x020000, 0x02a6dd, 0x02a700, 0x02b734, 0x02b740, 0x02b81d, 0x02b820, - 0x02cea1, 0x02ceb0, 0x02ebe0, 0x02f800, 0x02fa1d, 0x030000, 0x03134a)); + 0x016fe3, 0x017000, 0x0187f7, 0x018800, 0x018cd5, 0x018d00, 0x018d08, 0x01aff0, 0x01aff3, 0x01aff5, 0x01affb, 0x01affd, 0x01affe, 0x01b000, 0x01b122, 0x01b150, 0x01b152, + 0x01b164, 0x01b167, 0x01b170, 0x01b2fb, 0x01bc00, 0x01bc6a, 0x01bc70, 0x01bc7c, 0x01bc80, 0x01bc88, 0x01bc90, 0x01bc99, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, + 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, + 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, + 0x01d6c0, 0x01d6c2, 0x01d6da, 0x01d6dc, 0x01d6fa, 0x01d6fc, 0x01d714, 0x01d716, 0x01d734, 0x01d736, 0x01d74e, 0x01d750, 0x01d76e, 0x01d770, 0x01d788, 0x01d78a, 0x01d7a8, + 0x01d7aa, 0x01d7c2, 0x01d7c4, 0x01d7cb, 0x01df00, 0x01df1e, 0x01e100, 0x01e12c, 0x01e137, 0x01e13d, 0x01e14e, 0x01e14e, 0x01e290, 0x01e2ad, 0x01e2c0, 0x01e2eb, 0x01e7e0, + 0x01e7e6, 0x01e7e8, 0x01e7eb, 0x01e7ed, 0x01e7ee, 0x01e7f0, 0x01e7fe, 0x01e800, 0x01e8c4, 0x01e900, 0x01e943, 0x01e94b, 0x01e94b, 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, + 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, 0x01ee39, 0x01ee3b, 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, + 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, 0x01ee57, 0x01ee57, 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, + 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, 0x01ee72, 0x01ee74, 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, + 0x01ee7e, 0x01ee80, 0x01ee89, 0x01ee8b, 0x01ee9b, 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, 0x020000, 0x02a6df, 0x02a700, 0x02b738, 0x02b740, 0x02b81d, + 0x02b820, 0x02cea1, 0x02ceb0, 0x02ebe0, 0x02f800, 0x02fa1d, 0x030000, 0x03134a)); GENERAL_CATEGORIES.put("gc=M", CodePointSet.createNoDedup(0x000300, 0x00036f, 0x000483, 0x000489, 0x000591, 0x0005bd, 0x0005bf, 0x0005bf, 0x0005c1, 0x0005c2, 0x0005c4, 0x0005c5, 0x0005c7, 0x0005c7, 0x000610, 0x00061a, 0x00064b, 0x00065f, 0x000670, 0x000670, 0x0006d6, 0x0006dc, 0x0006df, 0x0006e4, 0x0006e7, 0x0006e8, 0x0006ea, 0x0006ed, 0x000711, 0x000711, 0x000730, 0x00074a, 0x0007a6, 0x0007b0, 0x0007eb, 0x0007f3, 0x0007fd, 0x0007fd, 0x000816, 0x000819, 0x00081b, 0x000823, 0x000825, 0x000827, 0x000829, 0x00082d, 0x000859, - 0x00085b, 0x0008d3, 0x0008e1, 0x0008e3, 0x000903, 0x00093a, 0x00093c, 0x00093e, 0x00094f, 0x000951, 0x000957, 0x000962, 0x000963, 0x000981, 0x000983, 0x0009bc, 0x0009bc, - 0x0009be, 0x0009c4, 0x0009c7, 0x0009c8, 0x0009cb, 0x0009cd, 0x0009d7, 0x0009d7, 0x0009e2, 0x0009e3, 0x0009fe, 0x0009fe, 0x000a01, 0x000a03, 0x000a3c, 0x000a3c, 0x000a3e, - 0x000a42, 0x000a47, 0x000a48, 0x000a4b, 0x000a4d, 0x000a51, 0x000a51, 0x000a70, 0x000a71, 0x000a75, 0x000a75, 0x000a81, 0x000a83, 0x000abc, 0x000abc, 0x000abe, 0x000ac5, - 0x000ac7, 0x000ac9, 0x000acb, 0x000acd, 0x000ae2, 0x000ae3, 0x000afa, 0x000aff, 0x000b01, 0x000b03, 0x000b3c, 0x000b3c, 0x000b3e, 0x000b44, 0x000b47, 0x000b48, 0x000b4b, - 0x000b4d, 0x000b55, 0x000b57, 0x000b62, 0x000b63, 0x000b82, 0x000b82, 0x000bbe, 0x000bc2, 0x000bc6, 0x000bc8, 0x000bca, 0x000bcd, 0x000bd7, 0x000bd7, 0x000c00, 0x000c04, - 0x000c3e, 0x000c44, 0x000c46, 0x000c48, 0x000c4a, 0x000c4d, 0x000c55, 0x000c56, 0x000c62, 0x000c63, 0x000c81, 0x000c83, 0x000cbc, 0x000cbc, 0x000cbe, 0x000cc4, 0x000cc6, - 0x000cc8, 0x000cca, 0x000ccd, 0x000cd5, 0x000cd6, 0x000ce2, 0x000ce3, 0x000d00, 0x000d03, 0x000d3b, 0x000d3c, 0x000d3e, 0x000d44, 0x000d46, 0x000d48, 0x000d4a, 0x000d4d, - 0x000d57, 0x000d57, 0x000d62, 0x000d63, 0x000d81, 0x000d83, 0x000dca, 0x000dca, 0x000dcf, 0x000dd4, 0x000dd6, 0x000dd6, 0x000dd8, 0x000ddf, 0x000df2, 0x000df3, 0x000e31, - 0x000e31, 0x000e34, 0x000e3a, 0x000e47, 0x000e4e, 0x000eb1, 0x000eb1, 0x000eb4, 0x000ebc, 0x000ec8, 0x000ecd, 0x000f18, 0x000f19, 0x000f35, 0x000f35, 0x000f37, 0x000f37, - 0x000f39, 0x000f39, 0x000f3e, 0x000f3f, 0x000f71, 0x000f84, 0x000f86, 0x000f87, 0x000f8d, 0x000f97, 0x000f99, 0x000fbc, 0x000fc6, 0x000fc6, 0x00102b, 0x00103e, 0x001056, - 0x001059, 0x00105e, 0x001060, 0x001062, 0x001064, 0x001067, 0x00106d, 0x001071, 0x001074, 0x001082, 0x00108d, 0x00108f, 0x00108f, 0x00109a, 0x00109d, 0x00135d, 0x00135f, - 0x001712, 0x001714, 0x001732, 0x001734, 0x001752, 0x001753, 0x001772, 0x001773, 0x0017b4, 0x0017d3, 0x0017dd, 0x0017dd, 0x00180b, 0x00180d, 0x001885, 0x001886, 0x0018a9, - 0x0018a9, 0x001920, 0x00192b, 0x001930, 0x00193b, 0x001a17, 0x001a1b, 0x001a55, 0x001a5e, 0x001a60, 0x001a7c, 0x001a7f, 0x001a7f, 0x001ab0, 0x001ac0, 0x001b00, 0x001b04, - 0x001b34, 0x001b44, 0x001b6b, 0x001b73, 0x001b80, 0x001b82, 0x001ba1, 0x001bad, 0x001be6, 0x001bf3, 0x001c24, 0x001c37, 0x001cd0, 0x001cd2, 0x001cd4, 0x001ce8, 0x001ced, - 0x001ced, 0x001cf4, 0x001cf4, 0x001cf7, 0x001cf9, 0x001dc0, 0x001df9, 0x001dfb, 0x001dff, 0x0020d0, 0x0020f0, 0x002cef, 0x002cf1, 0x002d7f, 0x002d7f, 0x002de0, 0x002dff, - 0x00302a, 0x00302f, 0x003099, 0x00309a, 0x00a66f, 0x00a672, 0x00a674, 0x00a67d, 0x00a69e, 0x00a69f, 0x00a6f0, 0x00a6f1, 0x00a802, 0x00a802, 0x00a806, 0x00a806, 0x00a80b, - 0x00a80b, 0x00a823, 0x00a827, 0x00a82c, 0x00a82c, 0x00a880, 0x00a881, 0x00a8b4, 0x00a8c5, 0x00a8e0, 0x00a8f1, 0x00a8ff, 0x00a8ff, 0x00a926, 0x00a92d, 0x00a947, 0x00a953, - 0x00a980, 0x00a983, 0x00a9b3, 0x00a9c0, 0x00a9e5, 0x00a9e5, 0x00aa29, 0x00aa36, 0x00aa43, 0x00aa43, 0x00aa4c, 0x00aa4d, 0x00aa7b, 0x00aa7d, 0x00aab0, 0x00aab0, 0x00aab2, - 0x00aab4, 0x00aab7, 0x00aab8, 0x00aabe, 0x00aabf, 0x00aac1, 0x00aac1, 0x00aaeb, 0x00aaef, 0x00aaf5, 0x00aaf6, 0x00abe3, 0x00abea, 0x00abec, 0x00abed, 0x00fb1e, 0x00fb1e, - 0x00fe00, 0x00fe0f, 0x00fe20, 0x00fe2f, 0x0101fd, 0x0101fd, 0x0102e0, 0x0102e0, 0x010376, 0x01037a, 0x010a01, 0x010a03, 0x010a05, 0x010a06, 0x010a0c, 0x010a0f, 0x010a38, - 0x010a3a, 0x010a3f, 0x010a3f, 0x010ae5, 0x010ae6, 0x010d24, 0x010d27, 0x010eab, 0x010eac, 0x010f46, 0x010f50, 0x011000, 0x011002, 0x011038, 0x011046, 0x01107f, 0x011082, - 0x0110b0, 0x0110ba, 0x011100, 0x011102, 0x011127, 0x011134, 0x011145, 0x011146, 0x011173, 0x011173, 0x011180, 0x011182, 0x0111b3, 0x0111c0, 0x0111c9, 0x0111cc, 0x0111ce, - 0x0111cf, 0x01122c, 0x011237, 0x01123e, 0x01123e, 0x0112df, 0x0112ea, 0x011300, 0x011303, 0x01133b, 0x01133c, 0x01133e, 0x011344, 0x011347, 0x011348, 0x01134b, 0x01134d, - 0x011357, 0x011357, 0x011362, 0x011363, 0x011366, 0x01136c, 0x011370, 0x011374, 0x011435, 0x011446, 0x01145e, 0x01145e, 0x0114b0, 0x0114c3, 0x0115af, 0x0115b5, 0x0115b8, - 0x0115c0, 0x0115dc, 0x0115dd, 0x011630, 0x011640, 0x0116ab, 0x0116b7, 0x01171d, 0x01172b, 0x01182c, 0x01183a, 0x011930, 0x011935, 0x011937, 0x011938, 0x01193b, 0x01193e, - 0x011940, 0x011940, 0x011942, 0x011943, 0x0119d1, 0x0119d7, 0x0119da, 0x0119e0, 0x0119e4, 0x0119e4, 0x011a01, 0x011a0a, 0x011a33, 0x011a39, 0x011a3b, 0x011a3e, 0x011a47, - 0x011a47, 0x011a51, 0x011a5b, 0x011a8a, 0x011a99, 0x011c2f, 0x011c36, 0x011c38, 0x011c3f, 0x011c92, 0x011ca7, 0x011ca9, 0x011cb6, 0x011d31, 0x011d36, 0x011d3a, 0x011d3a, - 0x011d3c, 0x011d3d, 0x011d3f, 0x011d45, 0x011d47, 0x011d47, 0x011d8a, 0x011d8e, 0x011d90, 0x011d91, 0x011d93, 0x011d97, 0x011ef3, 0x011ef6, 0x016af0, 0x016af4, 0x016b30, - 0x016b36, 0x016f4f, 0x016f4f, 0x016f51, 0x016f87, 0x016f8f, 0x016f92, 0x016fe4, 0x016fe4, 0x016ff0, 0x016ff1, 0x01bc9d, 0x01bc9e, 0x01d165, 0x01d169, 0x01d16d, 0x01d172, - 0x01d17b, 0x01d182, 0x01d185, 0x01d18b, 0x01d1aa, 0x01d1ad, 0x01d242, 0x01d244, 0x01da00, 0x01da36, 0x01da3b, 0x01da6c, 0x01da75, 0x01da75, 0x01da84, 0x01da84, 0x01da9b, - 0x01da9f, 0x01daa1, 0x01daaf, 0x01e000, 0x01e006, 0x01e008, 0x01e018, 0x01e01b, 0x01e021, 0x01e023, 0x01e024, 0x01e026, 0x01e02a, 0x01e130, 0x01e136, 0x01e2ec, 0x01e2ef, - 0x01e8d0, 0x01e8d6, 0x01e944, 0x01e94a, 0x0e0100, 0x0e01ef)); + 0x00085b, 0x000898, 0x00089f, 0x0008ca, 0x0008e1, 0x0008e3, 0x000903, 0x00093a, 0x00093c, 0x00093e, 0x00094f, 0x000951, 0x000957, 0x000962, 0x000963, 0x000981, 0x000983, + 0x0009bc, 0x0009bc, 0x0009be, 0x0009c4, 0x0009c7, 0x0009c8, 0x0009cb, 0x0009cd, 0x0009d7, 0x0009d7, 0x0009e2, 0x0009e3, 0x0009fe, 0x0009fe, 0x000a01, 0x000a03, 0x000a3c, + 0x000a3c, 0x000a3e, 0x000a42, 0x000a47, 0x000a48, 0x000a4b, 0x000a4d, 0x000a51, 0x000a51, 0x000a70, 0x000a71, 0x000a75, 0x000a75, 0x000a81, 0x000a83, 0x000abc, 0x000abc, + 0x000abe, 0x000ac5, 0x000ac7, 0x000ac9, 0x000acb, 0x000acd, 0x000ae2, 0x000ae3, 0x000afa, 0x000aff, 0x000b01, 0x000b03, 0x000b3c, 0x000b3c, 0x000b3e, 0x000b44, 0x000b47, + 0x000b48, 0x000b4b, 0x000b4d, 0x000b55, 0x000b57, 0x000b62, 0x000b63, 0x000b82, 0x000b82, 0x000bbe, 0x000bc2, 0x000bc6, 0x000bc8, 0x000bca, 0x000bcd, 0x000bd7, 0x000bd7, + 0x000c00, 0x000c04, 0x000c3c, 0x000c3c, 0x000c3e, 0x000c44, 0x000c46, 0x000c48, 0x000c4a, 0x000c4d, 0x000c55, 0x000c56, 0x000c62, 0x000c63, 0x000c81, 0x000c83, 0x000cbc, + 0x000cbc, 0x000cbe, 0x000cc4, 0x000cc6, 0x000cc8, 0x000cca, 0x000ccd, 0x000cd5, 0x000cd6, 0x000ce2, 0x000ce3, 0x000d00, 0x000d03, 0x000d3b, 0x000d3c, 0x000d3e, 0x000d44, + 0x000d46, 0x000d48, 0x000d4a, 0x000d4d, 0x000d57, 0x000d57, 0x000d62, 0x000d63, 0x000d81, 0x000d83, 0x000dca, 0x000dca, 0x000dcf, 0x000dd4, 0x000dd6, 0x000dd6, 0x000dd8, + 0x000ddf, 0x000df2, 0x000df3, 0x000e31, 0x000e31, 0x000e34, 0x000e3a, 0x000e47, 0x000e4e, 0x000eb1, 0x000eb1, 0x000eb4, 0x000ebc, 0x000ec8, 0x000ecd, 0x000f18, 0x000f19, + 0x000f35, 0x000f35, 0x000f37, 0x000f37, 0x000f39, 0x000f39, 0x000f3e, 0x000f3f, 0x000f71, 0x000f84, 0x000f86, 0x000f87, 0x000f8d, 0x000f97, 0x000f99, 0x000fbc, 0x000fc6, + 0x000fc6, 0x00102b, 0x00103e, 0x001056, 0x001059, 0x00105e, 0x001060, 0x001062, 0x001064, 0x001067, 0x00106d, 0x001071, 0x001074, 0x001082, 0x00108d, 0x00108f, 0x00108f, + 0x00109a, 0x00109d, 0x00135d, 0x00135f, 0x001712, 0x001715, 0x001732, 0x001734, 0x001752, 0x001753, 0x001772, 0x001773, 0x0017b4, 0x0017d3, 0x0017dd, 0x0017dd, 0x00180b, + 0x00180d, 0x00180f, 0x00180f, 0x001885, 0x001886, 0x0018a9, 0x0018a9, 0x001920, 0x00192b, 0x001930, 0x00193b, 0x001a17, 0x001a1b, 0x001a55, 0x001a5e, 0x001a60, 0x001a7c, + 0x001a7f, 0x001a7f, 0x001ab0, 0x001ace, 0x001b00, 0x001b04, 0x001b34, 0x001b44, 0x001b6b, 0x001b73, 0x001b80, 0x001b82, 0x001ba1, 0x001bad, 0x001be6, 0x001bf3, 0x001c24, + 0x001c37, 0x001cd0, 0x001cd2, 0x001cd4, 0x001ce8, 0x001ced, 0x001ced, 0x001cf4, 0x001cf4, 0x001cf7, 0x001cf9, 0x001dc0, 0x001dff, 0x0020d0, 0x0020f0, 0x002cef, 0x002cf1, + 0x002d7f, 0x002d7f, 0x002de0, 0x002dff, 0x00302a, 0x00302f, 0x003099, 0x00309a, 0x00a66f, 0x00a672, 0x00a674, 0x00a67d, 0x00a69e, 0x00a69f, 0x00a6f0, 0x00a6f1, 0x00a802, + 0x00a802, 0x00a806, 0x00a806, 0x00a80b, 0x00a80b, 0x00a823, 0x00a827, 0x00a82c, 0x00a82c, 0x00a880, 0x00a881, 0x00a8b4, 0x00a8c5, 0x00a8e0, 0x00a8f1, 0x00a8ff, 0x00a8ff, + 0x00a926, 0x00a92d, 0x00a947, 0x00a953, 0x00a980, 0x00a983, 0x00a9b3, 0x00a9c0, 0x00a9e5, 0x00a9e5, 0x00aa29, 0x00aa36, 0x00aa43, 0x00aa43, 0x00aa4c, 0x00aa4d, 0x00aa7b, + 0x00aa7d, 0x00aab0, 0x00aab0, 0x00aab2, 0x00aab4, 0x00aab7, 0x00aab8, 0x00aabe, 0x00aabf, 0x00aac1, 0x00aac1, 0x00aaeb, 0x00aaef, 0x00aaf5, 0x00aaf6, 0x00abe3, 0x00abea, + 0x00abec, 0x00abed, 0x00fb1e, 0x00fb1e, 0x00fe00, 0x00fe0f, 0x00fe20, 0x00fe2f, 0x0101fd, 0x0101fd, 0x0102e0, 0x0102e0, 0x010376, 0x01037a, 0x010a01, 0x010a03, 0x010a05, + 0x010a06, 0x010a0c, 0x010a0f, 0x010a38, 0x010a3a, 0x010a3f, 0x010a3f, 0x010ae5, 0x010ae6, 0x010d24, 0x010d27, 0x010eab, 0x010eac, 0x010f46, 0x010f50, 0x010f82, 0x010f85, + 0x011000, 0x011002, 0x011038, 0x011046, 0x011070, 0x011070, 0x011073, 0x011074, 0x01107f, 0x011082, 0x0110b0, 0x0110ba, 0x0110c2, 0x0110c2, 0x011100, 0x011102, 0x011127, + 0x011134, 0x011145, 0x011146, 0x011173, 0x011173, 0x011180, 0x011182, 0x0111b3, 0x0111c0, 0x0111c9, 0x0111cc, 0x0111ce, 0x0111cf, 0x01122c, 0x011237, 0x01123e, 0x01123e, + 0x0112df, 0x0112ea, 0x011300, 0x011303, 0x01133b, 0x01133c, 0x01133e, 0x011344, 0x011347, 0x011348, 0x01134b, 0x01134d, 0x011357, 0x011357, 0x011362, 0x011363, 0x011366, + 0x01136c, 0x011370, 0x011374, 0x011435, 0x011446, 0x01145e, 0x01145e, 0x0114b0, 0x0114c3, 0x0115af, 0x0115b5, 0x0115b8, 0x0115c0, 0x0115dc, 0x0115dd, 0x011630, 0x011640, + 0x0116ab, 0x0116b7, 0x01171d, 0x01172b, 0x01182c, 0x01183a, 0x011930, 0x011935, 0x011937, 0x011938, 0x01193b, 0x01193e, 0x011940, 0x011940, 0x011942, 0x011943, 0x0119d1, + 0x0119d7, 0x0119da, 0x0119e0, 0x0119e4, 0x0119e4, 0x011a01, 0x011a0a, 0x011a33, 0x011a39, 0x011a3b, 0x011a3e, 0x011a47, 0x011a47, 0x011a51, 0x011a5b, 0x011a8a, 0x011a99, + 0x011c2f, 0x011c36, 0x011c38, 0x011c3f, 0x011c92, 0x011ca7, 0x011ca9, 0x011cb6, 0x011d31, 0x011d36, 0x011d3a, 0x011d3a, 0x011d3c, 0x011d3d, 0x011d3f, 0x011d45, 0x011d47, + 0x011d47, 0x011d8a, 0x011d8e, 0x011d90, 0x011d91, 0x011d93, 0x011d97, 0x011ef3, 0x011ef6, 0x016af0, 0x016af4, 0x016b30, 0x016b36, 0x016f4f, 0x016f4f, 0x016f51, 0x016f87, + 0x016f8f, 0x016f92, 0x016fe4, 0x016fe4, 0x016ff0, 0x016ff1, 0x01bc9d, 0x01bc9e, 0x01cf00, 0x01cf2d, 0x01cf30, 0x01cf46, 0x01d165, 0x01d169, 0x01d16d, 0x01d172, 0x01d17b, + 0x01d182, 0x01d185, 0x01d18b, 0x01d1aa, 0x01d1ad, 0x01d242, 0x01d244, 0x01da00, 0x01da36, 0x01da3b, 0x01da6c, 0x01da75, 0x01da75, 0x01da84, 0x01da84, 0x01da9b, 0x01da9f, + 0x01daa1, 0x01daaf, 0x01e000, 0x01e006, 0x01e008, 0x01e018, 0x01e01b, 0x01e021, 0x01e023, 0x01e024, 0x01e026, 0x01e02a, 0x01e130, 0x01e136, 0x01e2ae, 0x01e2ae, 0x01e2ec, + 0x01e2ef, 0x01e8d0, 0x01e8d6, 0x01e944, 0x01e94a, 0x0e0100, 0x0e01ef)); GENERAL_CATEGORIES.put("gc=N", CodePointSet.createNoDedup(0x000030, 0x000039, 0x0000b2, 0x0000b3, 0x0000b9, 0x0000b9, 0x0000bc, 0x0000be, 0x000660, 0x000669, 0x0006f0, 0x0006f9, 0x0007c0, 0x0007c9, 0x000966, 0x00096f, 0x0009e6, 0x0009ef, 0x0009f4, 0x0009f9, 0x000a66, 0x000a6f, 0x000ae6, 0x000aef, 0x000b66, 0x000b6f, 0x000b72, 0x000b77, 0x000be6, 0x000bf2, 0x000c66, 0x000c6f, 0x000c78, 0x000c7e, 0x000ce6, 0x000cef, 0x000d58, 0x000d5e, 0x000d66, 0x000d78, 0x000de6, 0x000def, 0x000e50, 0x000e59, 0x000ed0, 0x000ed9, 0x000f20, @@ -192,76 +197,77 @@ static CodePointSet getGeneralCategory(String name) { 0x0109d2, 0x0109ff, 0x010a40, 0x010a48, 0x010a7d, 0x010a7e, 0x010a9d, 0x010a9f, 0x010aeb, 0x010aef, 0x010b58, 0x010b5f, 0x010b78, 0x010b7f, 0x010ba9, 0x010baf, 0x010cfa, 0x010cff, 0x010d30, 0x010d39, 0x010e60, 0x010e7e, 0x010f1d, 0x010f26, 0x010f51, 0x010f54, 0x010fc5, 0x010fcb, 0x011052, 0x01106f, 0x0110f0, 0x0110f9, 0x011136, 0x01113f, 0x0111d0, 0x0111d9, 0x0111e1, 0x0111f4, 0x0112f0, 0x0112f9, 0x011450, 0x011459, 0x0114d0, 0x0114d9, 0x011650, 0x011659, 0x0116c0, 0x0116c9, 0x011730, 0x01173b, 0x0118e0, - 0x0118f2, 0x011950, 0x011959, 0x011c50, 0x011c6c, 0x011d50, 0x011d59, 0x011da0, 0x011da9, 0x011fc0, 0x011fd4, 0x012400, 0x01246e, 0x016a60, 0x016a69, 0x016b50, 0x016b59, - 0x016b5b, 0x016b61, 0x016e80, 0x016e96, 0x01d2e0, 0x01d2f3, 0x01d360, 0x01d378, 0x01d7ce, 0x01d7ff, 0x01e140, 0x01e149, 0x01e2f0, 0x01e2f9, 0x01e8c7, 0x01e8cf, 0x01e950, - 0x01e959, 0x01ec71, 0x01ecab, 0x01ecad, 0x01ecaf, 0x01ecb1, 0x01ecb4, 0x01ed01, 0x01ed2d, 0x01ed2f, 0x01ed3d, 0x01f100, 0x01f10c, 0x01fbf0, 0x01fbf9)); + 0x0118f2, 0x011950, 0x011959, 0x011c50, 0x011c6c, 0x011d50, 0x011d59, 0x011da0, 0x011da9, 0x011fc0, 0x011fd4, 0x012400, 0x01246e, 0x016a60, 0x016a69, 0x016ac0, 0x016ac9, + 0x016b50, 0x016b59, 0x016b5b, 0x016b61, 0x016e80, 0x016e96, 0x01d2e0, 0x01d2f3, 0x01d360, 0x01d378, 0x01d7ce, 0x01d7ff, 0x01e140, 0x01e149, 0x01e2f0, 0x01e2f9, 0x01e8c7, + 0x01e8cf, 0x01e950, 0x01e959, 0x01ec71, 0x01ecab, 0x01ecad, 0x01ecaf, 0x01ecb1, 0x01ecb4, 0x01ed01, 0x01ed2d, 0x01ed2f, 0x01ed3d, 0x01f100, 0x01f10c, 0x01fbf0, 0x01fbf9)); GENERAL_CATEGORIES.put("gc=P", CodePointSet.createNoDedup(0x000021, 0x000023, 0x000025, 0x00002a, 0x00002c, 0x00002f, 0x00003a, 0x00003b, 0x00003f, 0x000040, 0x00005b, 0x00005d, 0x00005f, 0x00005f, 0x00007b, 0x00007b, 0x00007d, 0x00007d, 0x0000a1, 0x0000a1, 0x0000a7, 0x0000a7, 0x0000ab, 0x0000ab, 0x0000b6, 0x0000b7, 0x0000bb, 0x0000bb, 0x0000bf, 0x0000bf, 0x00037e, 0x00037e, 0x000387, 0x000387, 0x00055a, 0x00055f, 0x000589, 0x00058a, 0x0005be, 0x0005be, 0x0005c0, 0x0005c0, 0x0005c3, 0x0005c3, 0x0005c6, 0x0005c6, 0x0005f3, - 0x0005f4, 0x000609, 0x00060a, 0x00060c, 0x00060d, 0x00061b, 0x00061b, 0x00061e, 0x00061f, 0x00066a, 0x00066d, 0x0006d4, 0x0006d4, 0x000700, 0x00070d, 0x0007f7, 0x0007f9, + 0x0005f4, 0x000609, 0x00060a, 0x00060c, 0x00060d, 0x00061b, 0x00061b, 0x00061d, 0x00061f, 0x00066a, 0x00066d, 0x0006d4, 0x0006d4, 0x000700, 0x00070d, 0x0007f7, 0x0007f9, 0x000830, 0x00083e, 0x00085e, 0x00085e, 0x000964, 0x000965, 0x000970, 0x000970, 0x0009fd, 0x0009fd, 0x000a76, 0x000a76, 0x000af0, 0x000af0, 0x000c77, 0x000c77, 0x000c84, 0x000c84, 0x000df4, 0x000df4, 0x000e4f, 0x000e4f, 0x000e5a, 0x000e5b, 0x000f04, 0x000f12, 0x000f14, 0x000f14, 0x000f3a, 0x000f3d, 0x000f85, 0x000f85, 0x000fd0, 0x000fd4, 0x000fd9, 0x000fda, 0x00104a, 0x00104f, 0x0010fb, 0x0010fb, 0x001360, 0x001368, 0x001400, 0x001400, 0x00166e, 0x00166e, 0x00169b, 0x00169c, 0x0016eb, 0x0016ed, 0x001735, 0x001736, 0x0017d4, 0x0017d6, 0x0017d8, 0x0017da, 0x001800, 0x00180a, 0x001944, 0x001945, 0x001a1e, 0x001a1f, 0x001aa0, 0x001aa6, 0x001aa8, 0x001aad, 0x001b5a, 0x001b60, - 0x001bfc, 0x001bff, 0x001c3b, 0x001c3f, 0x001c7e, 0x001c7f, 0x001cc0, 0x001cc7, 0x001cd3, 0x001cd3, 0x002010, 0x002027, 0x002030, 0x002043, 0x002045, 0x002051, 0x002053, - 0x00205e, 0x00207d, 0x00207e, 0x00208d, 0x00208e, 0x002308, 0x00230b, 0x002329, 0x00232a, 0x002768, 0x002775, 0x0027c5, 0x0027c6, 0x0027e6, 0x0027ef, 0x002983, 0x002998, - 0x0029d8, 0x0029db, 0x0029fc, 0x0029fd, 0x002cf9, 0x002cfc, 0x002cfe, 0x002cff, 0x002d70, 0x002d70, 0x002e00, 0x002e2e, 0x002e30, 0x002e4f, 0x002e52, 0x002e52, 0x003001, - 0x003003, 0x003008, 0x003011, 0x003014, 0x00301f, 0x003030, 0x003030, 0x00303d, 0x00303d, 0x0030a0, 0x0030a0, 0x0030fb, 0x0030fb, 0x00a4fe, 0x00a4ff, 0x00a60d, 0x00a60f, - 0x00a673, 0x00a673, 0x00a67e, 0x00a67e, 0x00a6f2, 0x00a6f7, 0x00a874, 0x00a877, 0x00a8ce, 0x00a8cf, 0x00a8f8, 0x00a8fa, 0x00a8fc, 0x00a8fc, 0x00a92e, 0x00a92f, 0x00a95f, - 0x00a95f, 0x00a9c1, 0x00a9cd, 0x00a9de, 0x00a9df, 0x00aa5c, 0x00aa5f, 0x00aade, 0x00aadf, 0x00aaf0, 0x00aaf1, 0x00abeb, 0x00abeb, 0x00fd3e, 0x00fd3f, 0x00fe10, 0x00fe19, - 0x00fe30, 0x00fe52, 0x00fe54, 0x00fe61, 0x00fe63, 0x00fe63, 0x00fe68, 0x00fe68, 0x00fe6a, 0x00fe6b, 0x00ff01, 0x00ff03, 0x00ff05, 0x00ff0a, 0x00ff0c, 0x00ff0f, 0x00ff1a, - 0x00ff1b, 0x00ff1f, 0x00ff20, 0x00ff3b, 0x00ff3d, 0x00ff3f, 0x00ff3f, 0x00ff5b, 0x00ff5b, 0x00ff5d, 0x00ff5d, 0x00ff5f, 0x00ff65, 0x010100, 0x010102, 0x01039f, 0x01039f, - 0x0103d0, 0x0103d0, 0x01056f, 0x01056f, 0x010857, 0x010857, 0x01091f, 0x01091f, 0x01093f, 0x01093f, 0x010a50, 0x010a58, 0x010a7f, 0x010a7f, 0x010af0, 0x010af6, 0x010b39, - 0x010b3f, 0x010b99, 0x010b9c, 0x010ead, 0x010ead, 0x010f55, 0x010f59, 0x011047, 0x01104d, 0x0110bb, 0x0110bc, 0x0110be, 0x0110c1, 0x011140, 0x011143, 0x011174, 0x011175, - 0x0111c5, 0x0111c8, 0x0111cd, 0x0111cd, 0x0111db, 0x0111db, 0x0111dd, 0x0111df, 0x011238, 0x01123d, 0x0112a9, 0x0112a9, 0x01144b, 0x01144f, 0x01145a, 0x01145b, 0x01145d, - 0x01145d, 0x0114c6, 0x0114c6, 0x0115c1, 0x0115d7, 0x011641, 0x011643, 0x011660, 0x01166c, 0x01173c, 0x01173e, 0x01183b, 0x01183b, 0x011944, 0x011946, 0x0119e2, 0x0119e2, - 0x011a3f, 0x011a46, 0x011a9a, 0x011a9c, 0x011a9e, 0x011aa2, 0x011c41, 0x011c45, 0x011c70, 0x011c71, 0x011ef7, 0x011ef8, 0x011fff, 0x011fff, 0x012470, 0x012474, 0x016a6e, - 0x016a6f, 0x016af5, 0x016af5, 0x016b37, 0x016b3b, 0x016b44, 0x016b44, 0x016e97, 0x016e9a, 0x016fe2, 0x016fe2, 0x01bc9f, 0x01bc9f, 0x01da87, 0x01da8b, 0x01e95e, 0x01e95f)); + 0x001b7d, 0x001b7e, 0x001bfc, 0x001bff, 0x001c3b, 0x001c3f, 0x001c7e, 0x001c7f, 0x001cc0, 0x001cc7, 0x001cd3, 0x001cd3, 0x002010, 0x002027, 0x002030, 0x002043, 0x002045, + 0x002051, 0x002053, 0x00205e, 0x00207d, 0x00207e, 0x00208d, 0x00208e, 0x002308, 0x00230b, 0x002329, 0x00232a, 0x002768, 0x002775, 0x0027c5, 0x0027c6, 0x0027e6, 0x0027ef, + 0x002983, 0x002998, 0x0029d8, 0x0029db, 0x0029fc, 0x0029fd, 0x002cf9, 0x002cfc, 0x002cfe, 0x002cff, 0x002d70, 0x002d70, 0x002e00, 0x002e2e, 0x002e30, 0x002e4f, 0x002e52, + 0x002e5d, 0x003001, 0x003003, 0x003008, 0x003011, 0x003014, 0x00301f, 0x003030, 0x003030, 0x00303d, 0x00303d, 0x0030a0, 0x0030a0, 0x0030fb, 0x0030fb, 0x00a4fe, 0x00a4ff, + 0x00a60d, 0x00a60f, 0x00a673, 0x00a673, 0x00a67e, 0x00a67e, 0x00a6f2, 0x00a6f7, 0x00a874, 0x00a877, 0x00a8ce, 0x00a8cf, 0x00a8f8, 0x00a8fa, 0x00a8fc, 0x00a8fc, 0x00a92e, + 0x00a92f, 0x00a95f, 0x00a95f, 0x00a9c1, 0x00a9cd, 0x00a9de, 0x00a9df, 0x00aa5c, 0x00aa5f, 0x00aade, 0x00aadf, 0x00aaf0, 0x00aaf1, 0x00abeb, 0x00abeb, 0x00fd3e, 0x00fd3f, + 0x00fe10, 0x00fe19, 0x00fe30, 0x00fe52, 0x00fe54, 0x00fe61, 0x00fe63, 0x00fe63, 0x00fe68, 0x00fe68, 0x00fe6a, 0x00fe6b, 0x00ff01, 0x00ff03, 0x00ff05, 0x00ff0a, 0x00ff0c, + 0x00ff0f, 0x00ff1a, 0x00ff1b, 0x00ff1f, 0x00ff20, 0x00ff3b, 0x00ff3d, 0x00ff3f, 0x00ff3f, 0x00ff5b, 0x00ff5b, 0x00ff5d, 0x00ff5d, 0x00ff5f, 0x00ff65, 0x010100, 0x010102, + 0x01039f, 0x01039f, 0x0103d0, 0x0103d0, 0x01056f, 0x01056f, 0x010857, 0x010857, 0x01091f, 0x01091f, 0x01093f, 0x01093f, 0x010a50, 0x010a58, 0x010a7f, 0x010a7f, 0x010af0, + 0x010af6, 0x010b39, 0x010b3f, 0x010b99, 0x010b9c, 0x010ead, 0x010ead, 0x010f55, 0x010f59, 0x010f86, 0x010f89, 0x011047, 0x01104d, 0x0110bb, 0x0110bc, 0x0110be, 0x0110c1, + 0x011140, 0x011143, 0x011174, 0x011175, 0x0111c5, 0x0111c8, 0x0111cd, 0x0111cd, 0x0111db, 0x0111db, 0x0111dd, 0x0111df, 0x011238, 0x01123d, 0x0112a9, 0x0112a9, 0x01144b, + 0x01144f, 0x01145a, 0x01145b, 0x01145d, 0x01145d, 0x0114c6, 0x0114c6, 0x0115c1, 0x0115d7, 0x011641, 0x011643, 0x011660, 0x01166c, 0x0116b9, 0x0116b9, 0x01173c, 0x01173e, + 0x01183b, 0x01183b, 0x011944, 0x011946, 0x0119e2, 0x0119e2, 0x011a3f, 0x011a46, 0x011a9a, 0x011a9c, 0x011a9e, 0x011aa2, 0x011c41, 0x011c45, 0x011c70, 0x011c71, 0x011ef7, + 0x011ef8, 0x011fff, 0x011fff, 0x012470, 0x012474, 0x012ff1, 0x012ff2, 0x016a6e, 0x016a6f, 0x016af5, 0x016af5, 0x016b37, 0x016b3b, 0x016b44, 0x016b44, 0x016e97, 0x016e9a, + 0x016fe2, 0x016fe2, 0x01bc9f, 0x01bc9f, 0x01da87, 0x01da8b, 0x01e95e, 0x01e95f)); GENERAL_CATEGORIES.put("gc=S", CodePointSet.createNoDedup(0x000024, 0x000024, 0x00002b, 0x00002b, 0x00003c, 0x00003e, 0x00005e, 0x00005e, 0x000060, 0x000060, 0x00007c, 0x00007c, 0x00007e, 0x00007e, 0x0000a2, 0x0000a6, 0x0000a8, 0x0000a9, 0x0000ac, 0x0000ac, 0x0000ae, 0x0000b1, 0x0000b4, 0x0000b4, 0x0000b8, 0x0000b8, 0x0000d7, 0x0000d7, 0x0000f7, 0x0000f7, 0x0002c2, 0x0002c5, 0x0002d2, 0x0002df, 0x0002e5, 0x0002eb, 0x0002ed, 0x0002ed, 0x0002ef, 0x0002ff, 0x000375, 0x000375, 0x000384, 0x000385, 0x0003f6, 0x0003f6, 0x000482, 0x000482, 0x00058d, 0x00058f, 0x000606, 0x000608, 0x00060b, 0x00060b, 0x00060e, 0x00060f, 0x0006de, 0x0006de, 0x0006e9, 0x0006e9, 0x0006fd, 0x0006fe, 0x0007f6, 0x0007f6, - 0x0007fe, 0x0007ff, 0x0009f2, 0x0009f3, 0x0009fa, 0x0009fb, 0x000af1, 0x000af1, 0x000b70, 0x000b70, 0x000bf3, 0x000bfa, 0x000c7f, 0x000c7f, 0x000d4f, 0x000d4f, 0x000d79, - 0x000d79, 0x000e3f, 0x000e3f, 0x000f01, 0x000f03, 0x000f13, 0x000f13, 0x000f15, 0x000f17, 0x000f1a, 0x000f1f, 0x000f34, 0x000f34, 0x000f36, 0x000f36, 0x000f38, 0x000f38, - 0x000fbe, 0x000fc5, 0x000fc7, 0x000fcc, 0x000fce, 0x000fcf, 0x000fd5, 0x000fd8, 0x00109e, 0x00109f, 0x001390, 0x001399, 0x00166d, 0x00166d, 0x0017db, 0x0017db, 0x001940, - 0x001940, 0x0019de, 0x0019ff, 0x001b61, 0x001b6a, 0x001b74, 0x001b7c, 0x001fbd, 0x001fbd, 0x001fbf, 0x001fc1, 0x001fcd, 0x001fcf, 0x001fdd, 0x001fdf, 0x001fed, 0x001fef, - 0x001ffd, 0x001ffe, 0x002044, 0x002044, 0x002052, 0x002052, 0x00207a, 0x00207c, 0x00208a, 0x00208c, 0x0020a0, 0x0020bf, 0x002100, 0x002101, 0x002103, 0x002106, 0x002108, - 0x002109, 0x002114, 0x002114, 0x002116, 0x002118, 0x00211e, 0x002123, 0x002125, 0x002125, 0x002127, 0x002127, 0x002129, 0x002129, 0x00212e, 0x00212e, 0x00213a, 0x00213b, - 0x002140, 0x002144, 0x00214a, 0x00214d, 0x00214f, 0x00214f, 0x00218a, 0x00218b, 0x002190, 0x002307, 0x00230c, 0x002328, 0x00232b, 0x002426, 0x002440, 0x00244a, 0x00249c, - 0x0024e9, 0x002500, 0x002767, 0x002794, 0x0027c4, 0x0027c7, 0x0027e5, 0x0027f0, 0x002982, 0x002999, 0x0029d7, 0x0029dc, 0x0029fb, 0x0029fe, 0x002b73, 0x002b76, 0x002b95, - 0x002b97, 0x002bff, 0x002ce5, 0x002cea, 0x002e50, 0x002e51, 0x002e80, 0x002e99, 0x002e9b, 0x002ef3, 0x002f00, 0x002fd5, 0x002ff0, 0x002ffb, 0x003004, 0x003004, 0x003012, - 0x003013, 0x003020, 0x003020, 0x003036, 0x003037, 0x00303e, 0x00303f, 0x00309b, 0x00309c, 0x003190, 0x003191, 0x003196, 0x00319f, 0x0031c0, 0x0031e3, 0x003200, 0x00321e, - 0x00322a, 0x003247, 0x003250, 0x003250, 0x003260, 0x00327f, 0x00328a, 0x0032b0, 0x0032c0, 0x0033ff, 0x004dc0, 0x004dff, 0x00a490, 0x00a4c6, 0x00a700, 0x00a716, 0x00a720, - 0x00a721, 0x00a789, 0x00a78a, 0x00a828, 0x00a82b, 0x00a836, 0x00a839, 0x00aa77, 0x00aa79, 0x00ab5b, 0x00ab5b, 0x00ab6a, 0x00ab6b, 0x00fb29, 0x00fb29, 0x00fbb2, 0x00fbc1, - 0x00fdfc, 0x00fdfd, 0x00fe62, 0x00fe62, 0x00fe64, 0x00fe66, 0x00fe69, 0x00fe69, 0x00ff04, 0x00ff04, 0x00ff0b, 0x00ff0b, 0x00ff1c, 0x00ff1e, 0x00ff3e, 0x00ff3e, 0x00ff40, - 0x00ff40, 0x00ff5c, 0x00ff5c, 0x00ff5e, 0x00ff5e, 0x00ffe0, 0x00ffe6, 0x00ffe8, 0x00ffee, 0x00fffc, 0x00fffd, 0x010137, 0x01013f, 0x010179, 0x010189, 0x01018c, 0x01018e, - 0x010190, 0x01019c, 0x0101a0, 0x0101a0, 0x0101d0, 0x0101fc, 0x010877, 0x010878, 0x010ac8, 0x010ac8, 0x01173f, 0x01173f, 0x011fd5, 0x011ff1, 0x016b3c, 0x016b3f, 0x016b45, - 0x016b45, 0x01bc9c, 0x01bc9c, 0x01d000, 0x01d0f5, 0x01d100, 0x01d126, 0x01d129, 0x01d164, 0x01d16a, 0x01d16c, 0x01d183, 0x01d184, 0x01d18c, 0x01d1a9, 0x01d1ae, 0x01d1e8, - 0x01d200, 0x01d241, 0x01d245, 0x01d245, 0x01d300, 0x01d356, 0x01d6c1, 0x01d6c1, 0x01d6db, 0x01d6db, 0x01d6fb, 0x01d6fb, 0x01d715, 0x01d715, 0x01d735, 0x01d735, 0x01d74f, - 0x01d74f, 0x01d76f, 0x01d76f, 0x01d789, 0x01d789, 0x01d7a9, 0x01d7a9, 0x01d7c3, 0x01d7c3, 0x01d800, 0x01d9ff, 0x01da37, 0x01da3a, 0x01da6d, 0x01da74, 0x01da76, 0x01da83, - 0x01da85, 0x01da86, 0x01e14f, 0x01e14f, 0x01e2ff, 0x01e2ff, 0x01ecac, 0x01ecac, 0x01ecb0, 0x01ecb0, 0x01ed2e, 0x01ed2e, 0x01eef0, 0x01eef1, 0x01f000, 0x01f02b, 0x01f030, - 0x01f093, 0x01f0a0, 0x01f0ae, 0x01f0b1, 0x01f0bf, 0x01f0c1, 0x01f0cf, 0x01f0d1, 0x01f0f5, 0x01f10d, 0x01f1ad, 0x01f1e6, 0x01f202, 0x01f210, 0x01f23b, 0x01f240, 0x01f248, - 0x01f250, 0x01f251, 0x01f260, 0x01f265, 0x01f300, 0x01f6d7, 0x01f6e0, 0x01f6ec, 0x01f6f0, 0x01f6fc, 0x01f700, 0x01f773, 0x01f780, 0x01f7d8, 0x01f7e0, 0x01f7eb, 0x01f800, - 0x01f80b, 0x01f810, 0x01f847, 0x01f850, 0x01f859, 0x01f860, 0x01f887, 0x01f890, 0x01f8ad, 0x01f8b0, 0x01f8b1, 0x01f900, 0x01f978, 0x01f97a, 0x01f9cb, 0x01f9cd, 0x01fa53, - 0x01fa60, 0x01fa6d, 0x01fa70, 0x01fa74, 0x01fa78, 0x01fa7a, 0x01fa80, 0x01fa86, 0x01fa90, 0x01faa8, 0x01fab0, 0x01fab6, 0x01fac0, 0x01fac2, 0x01fad0, 0x01fad6, 0x01fb00, - 0x01fb92, 0x01fb94, 0x01fbca)); + 0x0007fe, 0x0007ff, 0x000888, 0x000888, 0x0009f2, 0x0009f3, 0x0009fa, 0x0009fb, 0x000af1, 0x000af1, 0x000b70, 0x000b70, 0x000bf3, 0x000bfa, 0x000c7f, 0x000c7f, 0x000d4f, + 0x000d4f, 0x000d79, 0x000d79, 0x000e3f, 0x000e3f, 0x000f01, 0x000f03, 0x000f13, 0x000f13, 0x000f15, 0x000f17, 0x000f1a, 0x000f1f, 0x000f34, 0x000f34, 0x000f36, 0x000f36, + 0x000f38, 0x000f38, 0x000fbe, 0x000fc5, 0x000fc7, 0x000fcc, 0x000fce, 0x000fcf, 0x000fd5, 0x000fd8, 0x00109e, 0x00109f, 0x001390, 0x001399, 0x00166d, 0x00166d, 0x0017db, + 0x0017db, 0x001940, 0x001940, 0x0019de, 0x0019ff, 0x001b61, 0x001b6a, 0x001b74, 0x001b7c, 0x001fbd, 0x001fbd, 0x001fbf, 0x001fc1, 0x001fcd, 0x001fcf, 0x001fdd, 0x001fdf, + 0x001fed, 0x001fef, 0x001ffd, 0x001ffe, 0x002044, 0x002044, 0x002052, 0x002052, 0x00207a, 0x00207c, 0x00208a, 0x00208c, 0x0020a0, 0x0020c0, 0x002100, 0x002101, 0x002103, + 0x002106, 0x002108, 0x002109, 0x002114, 0x002114, 0x002116, 0x002118, 0x00211e, 0x002123, 0x002125, 0x002125, 0x002127, 0x002127, 0x002129, 0x002129, 0x00212e, 0x00212e, + 0x00213a, 0x00213b, 0x002140, 0x002144, 0x00214a, 0x00214d, 0x00214f, 0x00214f, 0x00218a, 0x00218b, 0x002190, 0x002307, 0x00230c, 0x002328, 0x00232b, 0x002426, 0x002440, + 0x00244a, 0x00249c, 0x0024e9, 0x002500, 0x002767, 0x002794, 0x0027c4, 0x0027c7, 0x0027e5, 0x0027f0, 0x002982, 0x002999, 0x0029d7, 0x0029dc, 0x0029fb, 0x0029fe, 0x002b73, + 0x002b76, 0x002b95, 0x002b97, 0x002bff, 0x002ce5, 0x002cea, 0x002e50, 0x002e51, 0x002e80, 0x002e99, 0x002e9b, 0x002ef3, 0x002f00, 0x002fd5, 0x002ff0, 0x002ffb, 0x003004, + 0x003004, 0x003012, 0x003013, 0x003020, 0x003020, 0x003036, 0x003037, 0x00303e, 0x00303f, 0x00309b, 0x00309c, 0x003190, 0x003191, 0x003196, 0x00319f, 0x0031c0, 0x0031e3, + 0x003200, 0x00321e, 0x00322a, 0x003247, 0x003250, 0x003250, 0x003260, 0x00327f, 0x00328a, 0x0032b0, 0x0032c0, 0x0033ff, 0x004dc0, 0x004dff, 0x00a490, 0x00a4c6, 0x00a700, + 0x00a716, 0x00a720, 0x00a721, 0x00a789, 0x00a78a, 0x00a828, 0x00a82b, 0x00a836, 0x00a839, 0x00aa77, 0x00aa79, 0x00ab5b, 0x00ab5b, 0x00ab6a, 0x00ab6b, 0x00fb29, 0x00fb29, + 0x00fbb2, 0x00fbc2, 0x00fd40, 0x00fd4f, 0x00fdcf, 0x00fdcf, 0x00fdfc, 0x00fdff, 0x00fe62, 0x00fe62, 0x00fe64, 0x00fe66, 0x00fe69, 0x00fe69, 0x00ff04, 0x00ff04, 0x00ff0b, + 0x00ff0b, 0x00ff1c, 0x00ff1e, 0x00ff3e, 0x00ff3e, 0x00ff40, 0x00ff40, 0x00ff5c, 0x00ff5c, 0x00ff5e, 0x00ff5e, 0x00ffe0, 0x00ffe6, 0x00ffe8, 0x00ffee, 0x00fffc, 0x00fffd, + 0x010137, 0x01013f, 0x010179, 0x010189, 0x01018c, 0x01018e, 0x010190, 0x01019c, 0x0101a0, 0x0101a0, 0x0101d0, 0x0101fc, 0x010877, 0x010878, 0x010ac8, 0x010ac8, 0x01173f, + 0x01173f, 0x011fd5, 0x011ff1, 0x016b3c, 0x016b3f, 0x016b45, 0x016b45, 0x01bc9c, 0x01bc9c, 0x01cf50, 0x01cfc3, 0x01d000, 0x01d0f5, 0x01d100, 0x01d126, 0x01d129, 0x01d164, + 0x01d16a, 0x01d16c, 0x01d183, 0x01d184, 0x01d18c, 0x01d1a9, 0x01d1ae, 0x01d1ea, 0x01d200, 0x01d241, 0x01d245, 0x01d245, 0x01d300, 0x01d356, 0x01d6c1, 0x01d6c1, 0x01d6db, + 0x01d6db, 0x01d6fb, 0x01d6fb, 0x01d715, 0x01d715, 0x01d735, 0x01d735, 0x01d74f, 0x01d74f, 0x01d76f, 0x01d76f, 0x01d789, 0x01d789, 0x01d7a9, 0x01d7a9, 0x01d7c3, 0x01d7c3, + 0x01d800, 0x01d9ff, 0x01da37, 0x01da3a, 0x01da6d, 0x01da74, 0x01da76, 0x01da83, 0x01da85, 0x01da86, 0x01e14f, 0x01e14f, 0x01e2ff, 0x01e2ff, 0x01ecac, 0x01ecac, 0x01ecb0, + 0x01ecb0, 0x01ed2e, 0x01ed2e, 0x01eef0, 0x01eef1, 0x01f000, 0x01f02b, 0x01f030, 0x01f093, 0x01f0a0, 0x01f0ae, 0x01f0b1, 0x01f0bf, 0x01f0c1, 0x01f0cf, 0x01f0d1, 0x01f0f5, + 0x01f10d, 0x01f1ad, 0x01f1e6, 0x01f202, 0x01f210, 0x01f23b, 0x01f240, 0x01f248, 0x01f250, 0x01f251, 0x01f260, 0x01f265, 0x01f300, 0x01f6d7, 0x01f6dd, 0x01f6ec, 0x01f6f0, + 0x01f6fc, 0x01f700, 0x01f773, 0x01f780, 0x01f7d8, 0x01f7e0, 0x01f7eb, 0x01f7f0, 0x01f7f0, 0x01f800, 0x01f80b, 0x01f810, 0x01f847, 0x01f850, 0x01f859, 0x01f860, 0x01f887, + 0x01f890, 0x01f8ad, 0x01f8b0, 0x01f8b1, 0x01f900, 0x01fa53, 0x01fa60, 0x01fa6d, 0x01fa70, 0x01fa74, 0x01fa78, 0x01fa7c, 0x01fa80, 0x01fa86, 0x01fa90, 0x01faac, 0x01fab0, + 0x01faba, 0x01fac0, 0x01fac5, 0x01fad0, 0x01fad9, 0x01fae0, 0x01fae7, 0x01faf0, 0x01faf6, 0x01fb00, 0x01fb92, 0x01fb94, 0x01fbca)); GENERAL_CATEGORIES.put("gc=Z", CodePointSet.createNoDedup(0x000020, 0x000020, 0x0000a0, 0x0000a0, 0x001680, 0x001680, 0x002000, 0x00200a, 0x002028, 0x002029, 0x00202f, 0x00202f, 0x00205f, 0x00205f, 0x003000, 0x003000)); GENERAL_CATEGORIES.put("gc=C", CodePointSet.createNoDedup(0x000000, 0x00001f, 0x00007f, 0x00009f, 0x0000ad, 0x0000ad, 0x000378, 0x000379, 0x000380, 0x000383, 0x00038b, 0x00038b, 0x00038d, 0x00038d, 0x0003a2, 0x0003a2, 0x000530, 0x000530, 0x000557, 0x000558, 0x00058b, 0x00058c, 0x000590, 0x000590, 0x0005c8, 0x0005cf, 0x0005eb, 0x0005ee, 0x0005f5, 0x000605, - 0x00061c, 0x00061d, 0x0006dd, 0x0006dd, 0x00070e, 0x00070f, 0x00074b, 0x00074c, 0x0007b2, 0x0007bf, 0x0007fb, 0x0007fc, 0x00082e, 0x00082f, 0x00083f, 0x00083f, 0x00085c, - 0x00085d, 0x00085f, 0x00085f, 0x00086b, 0x00089f, 0x0008b5, 0x0008b5, 0x0008c8, 0x0008d2, 0x0008e2, 0x0008e2, 0x000984, 0x000984, 0x00098d, 0x00098e, 0x000991, 0x000992, - 0x0009a9, 0x0009a9, 0x0009b1, 0x0009b1, 0x0009b3, 0x0009b5, 0x0009ba, 0x0009bb, 0x0009c5, 0x0009c6, 0x0009c9, 0x0009ca, 0x0009cf, 0x0009d6, 0x0009d8, 0x0009db, 0x0009de, - 0x0009de, 0x0009e4, 0x0009e5, 0x0009ff, 0x000a00, 0x000a04, 0x000a04, 0x000a0b, 0x000a0e, 0x000a11, 0x000a12, 0x000a29, 0x000a29, 0x000a31, 0x000a31, 0x000a34, 0x000a34, - 0x000a37, 0x000a37, 0x000a3a, 0x000a3b, 0x000a3d, 0x000a3d, 0x000a43, 0x000a46, 0x000a49, 0x000a4a, 0x000a4e, 0x000a50, 0x000a52, 0x000a58, 0x000a5d, 0x000a5d, 0x000a5f, - 0x000a65, 0x000a77, 0x000a80, 0x000a84, 0x000a84, 0x000a8e, 0x000a8e, 0x000a92, 0x000a92, 0x000aa9, 0x000aa9, 0x000ab1, 0x000ab1, 0x000ab4, 0x000ab4, 0x000aba, 0x000abb, - 0x000ac6, 0x000ac6, 0x000aca, 0x000aca, 0x000ace, 0x000acf, 0x000ad1, 0x000adf, 0x000ae4, 0x000ae5, 0x000af2, 0x000af8, 0x000b00, 0x000b00, 0x000b04, 0x000b04, 0x000b0d, - 0x000b0e, 0x000b11, 0x000b12, 0x000b29, 0x000b29, 0x000b31, 0x000b31, 0x000b34, 0x000b34, 0x000b3a, 0x000b3b, 0x000b45, 0x000b46, 0x000b49, 0x000b4a, 0x000b4e, 0x000b54, - 0x000b58, 0x000b5b, 0x000b5e, 0x000b5e, 0x000b64, 0x000b65, 0x000b78, 0x000b81, 0x000b84, 0x000b84, 0x000b8b, 0x000b8d, 0x000b91, 0x000b91, 0x000b96, 0x000b98, 0x000b9b, - 0x000b9b, 0x000b9d, 0x000b9d, 0x000ba0, 0x000ba2, 0x000ba5, 0x000ba7, 0x000bab, 0x000bad, 0x000bba, 0x000bbd, 0x000bc3, 0x000bc5, 0x000bc9, 0x000bc9, 0x000bce, 0x000bcf, - 0x000bd1, 0x000bd6, 0x000bd8, 0x000be5, 0x000bfb, 0x000bff, 0x000c0d, 0x000c0d, 0x000c11, 0x000c11, 0x000c29, 0x000c29, 0x000c3a, 0x000c3c, 0x000c45, 0x000c45, 0x000c49, - 0x000c49, 0x000c4e, 0x000c54, 0x000c57, 0x000c57, 0x000c5b, 0x000c5f, 0x000c64, 0x000c65, 0x000c70, 0x000c76, 0x000c8d, 0x000c8d, 0x000c91, 0x000c91, 0x000ca9, 0x000ca9, - 0x000cb4, 0x000cb4, 0x000cba, 0x000cbb, 0x000cc5, 0x000cc5, 0x000cc9, 0x000cc9, 0x000cce, 0x000cd4, 0x000cd7, 0x000cdd, 0x000cdf, 0x000cdf, 0x000ce4, 0x000ce5, 0x000cf0, + 0x00061c, 0x00061c, 0x0006dd, 0x0006dd, 0x00070e, 0x00070f, 0x00074b, 0x00074c, 0x0007b2, 0x0007bf, 0x0007fb, 0x0007fc, 0x00082e, 0x00082f, 0x00083f, 0x00083f, 0x00085c, + 0x00085d, 0x00085f, 0x00085f, 0x00086b, 0x00086f, 0x00088f, 0x000897, 0x0008e2, 0x0008e2, 0x000984, 0x000984, 0x00098d, 0x00098e, 0x000991, 0x000992, 0x0009a9, 0x0009a9, + 0x0009b1, 0x0009b1, 0x0009b3, 0x0009b5, 0x0009ba, 0x0009bb, 0x0009c5, 0x0009c6, 0x0009c9, 0x0009ca, 0x0009cf, 0x0009d6, 0x0009d8, 0x0009db, 0x0009de, 0x0009de, 0x0009e4, + 0x0009e5, 0x0009ff, 0x000a00, 0x000a04, 0x000a04, 0x000a0b, 0x000a0e, 0x000a11, 0x000a12, 0x000a29, 0x000a29, 0x000a31, 0x000a31, 0x000a34, 0x000a34, 0x000a37, 0x000a37, + 0x000a3a, 0x000a3b, 0x000a3d, 0x000a3d, 0x000a43, 0x000a46, 0x000a49, 0x000a4a, 0x000a4e, 0x000a50, 0x000a52, 0x000a58, 0x000a5d, 0x000a5d, 0x000a5f, 0x000a65, 0x000a77, + 0x000a80, 0x000a84, 0x000a84, 0x000a8e, 0x000a8e, 0x000a92, 0x000a92, 0x000aa9, 0x000aa9, 0x000ab1, 0x000ab1, 0x000ab4, 0x000ab4, 0x000aba, 0x000abb, 0x000ac6, 0x000ac6, + 0x000aca, 0x000aca, 0x000ace, 0x000acf, 0x000ad1, 0x000adf, 0x000ae4, 0x000ae5, 0x000af2, 0x000af8, 0x000b00, 0x000b00, 0x000b04, 0x000b04, 0x000b0d, 0x000b0e, 0x000b11, + 0x000b12, 0x000b29, 0x000b29, 0x000b31, 0x000b31, 0x000b34, 0x000b34, 0x000b3a, 0x000b3b, 0x000b45, 0x000b46, 0x000b49, 0x000b4a, 0x000b4e, 0x000b54, 0x000b58, 0x000b5b, + 0x000b5e, 0x000b5e, 0x000b64, 0x000b65, 0x000b78, 0x000b81, 0x000b84, 0x000b84, 0x000b8b, 0x000b8d, 0x000b91, 0x000b91, 0x000b96, 0x000b98, 0x000b9b, 0x000b9b, 0x000b9d, + 0x000b9d, 0x000ba0, 0x000ba2, 0x000ba5, 0x000ba7, 0x000bab, 0x000bad, 0x000bba, 0x000bbd, 0x000bc3, 0x000bc5, 0x000bc9, 0x000bc9, 0x000bce, 0x000bcf, 0x000bd1, 0x000bd6, + 0x000bd8, 0x000be5, 0x000bfb, 0x000bff, 0x000c0d, 0x000c0d, 0x000c11, 0x000c11, 0x000c29, 0x000c29, 0x000c3a, 0x000c3b, 0x000c45, 0x000c45, 0x000c49, 0x000c49, 0x000c4e, + 0x000c54, 0x000c57, 0x000c57, 0x000c5b, 0x000c5c, 0x000c5e, 0x000c5f, 0x000c64, 0x000c65, 0x000c70, 0x000c76, 0x000c8d, 0x000c8d, 0x000c91, 0x000c91, 0x000ca9, 0x000ca9, + 0x000cb4, 0x000cb4, 0x000cba, 0x000cbb, 0x000cc5, 0x000cc5, 0x000cc9, 0x000cc9, 0x000cce, 0x000cd4, 0x000cd7, 0x000cdc, 0x000cdf, 0x000cdf, 0x000ce4, 0x000ce5, 0x000cf0, 0x000cf0, 0x000cf3, 0x000cff, 0x000d0d, 0x000d0d, 0x000d11, 0x000d11, 0x000d45, 0x000d45, 0x000d49, 0x000d49, 0x000d50, 0x000d53, 0x000d64, 0x000d65, 0x000d80, 0x000d80, 0x000d84, 0x000d84, 0x000d97, 0x000d99, 0x000db2, 0x000db2, 0x000dbc, 0x000dbc, 0x000dbe, 0x000dbf, 0x000dc7, 0x000dc9, 0x000dcb, 0x000dce, 0x000dd5, 0x000dd5, 0x000dd7, 0x000dd7, 0x000de0, 0x000de5, 0x000df0, 0x000df1, 0x000df5, 0x000e00, 0x000e3b, 0x000e3e, 0x000e5c, 0x000e80, 0x000e83, 0x000e83, 0x000e85, 0x000e85, 0x000e8b, 0x000e8b, @@ -269,64 +275,66 @@ static CodePointSet getGeneralCategory(String name) { 0x000f48, 0x000f6d, 0x000f70, 0x000f98, 0x000f98, 0x000fbd, 0x000fbd, 0x000fcd, 0x000fcd, 0x000fdb, 0x000fff, 0x0010c6, 0x0010c6, 0x0010c8, 0x0010cc, 0x0010ce, 0x0010cf, 0x001249, 0x001249, 0x00124e, 0x00124f, 0x001257, 0x001257, 0x001259, 0x001259, 0x00125e, 0x00125f, 0x001289, 0x001289, 0x00128e, 0x00128f, 0x0012b1, 0x0012b1, 0x0012b6, 0x0012b7, 0x0012bf, 0x0012bf, 0x0012c1, 0x0012c1, 0x0012c6, 0x0012c7, 0x0012d7, 0x0012d7, 0x001311, 0x001311, 0x001316, 0x001317, 0x00135b, 0x00135c, 0x00137d, 0x00137f, - 0x00139a, 0x00139f, 0x0013f6, 0x0013f7, 0x0013fe, 0x0013ff, 0x00169d, 0x00169f, 0x0016f9, 0x0016ff, 0x00170d, 0x00170d, 0x001715, 0x00171f, 0x001737, 0x00173f, 0x001754, - 0x00175f, 0x00176d, 0x00176d, 0x001771, 0x001771, 0x001774, 0x00177f, 0x0017de, 0x0017df, 0x0017ea, 0x0017ef, 0x0017fa, 0x0017ff, 0x00180e, 0x00180f, 0x00181a, 0x00181f, - 0x001879, 0x00187f, 0x0018ab, 0x0018af, 0x0018f6, 0x0018ff, 0x00191f, 0x00191f, 0x00192c, 0x00192f, 0x00193c, 0x00193f, 0x001941, 0x001943, 0x00196e, 0x00196f, 0x001975, - 0x00197f, 0x0019ac, 0x0019af, 0x0019ca, 0x0019cf, 0x0019db, 0x0019dd, 0x001a1c, 0x001a1d, 0x001a5f, 0x001a5f, 0x001a7d, 0x001a7e, 0x001a8a, 0x001a8f, 0x001a9a, 0x001a9f, - 0x001aae, 0x001aaf, 0x001ac1, 0x001aff, 0x001b4c, 0x001b4f, 0x001b7d, 0x001b7f, 0x001bf4, 0x001bfb, 0x001c38, 0x001c3a, 0x001c4a, 0x001c4c, 0x001c89, 0x001c8f, 0x001cbb, - 0x001cbc, 0x001cc8, 0x001ccf, 0x001cfb, 0x001cff, 0x001dfa, 0x001dfa, 0x001f16, 0x001f17, 0x001f1e, 0x001f1f, 0x001f46, 0x001f47, 0x001f4e, 0x001f4f, 0x001f58, 0x001f58, - 0x001f5a, 0x001f5a, 0x001f5c, 0x001f5c, 0x001f5e, 0x001f5e, 0x001f7e, 0x001f7f, 0x001fb5, 0x001fb5, 0x001fc5, 0x001fc5, 0x001fd4, 0x001fd5, 0x001fdc, 0x001fdc, 0x001ff0, - 0x001ff1, 0x001ff5, 0x001ff5, 0x001fff, 0x001fff, 0x00200b, 0x00200f, 0x00202a, 0x00202e, 0x002060, 0x00206f, 0x002072, 0x002073, 0x00208f, 0x00208f, 0x00209d, 0x00209f, - 0x0020c0, 0x0020cf, 0x0020f1, 0x0020ff, 0x00218c, 0x00218f, 0x002427, 0x00243f, 0x00244b, 0x00245f, 0x002b74, 0x002b75, 0x002b96, 0x002b96, 0x002c2f, 0x002c2f, 0x002c5f, - 0x002c5f, 0x002cf4, 0x002cf8, 0x002d26, 0x002d26, 0x002d28, 0x002d2c, 0x002d2e, 0x002d2f, 0x002d68, 0x002d6e, 0x002d71, 0x002d7e, 0x002d97, 0x002d9f, 0x002da7, 0x002da7, - 0x002daf, 0x002daf, 0x002db7, 0x002db7, 0x002dbf, 0x002dbf, 0x002dc7, 0x002dc7, 0x002dcf, 0x002dcf, 0x002dd7, 0x002dd7, 0x002ddf, 0x002ddf, 0x002e53, 0x002e7f, 0x002e9a, - 0x002e9a, 0x002ef4, 0x002eff, 0x002fd6, 0x002fef, 0x002ffc, 0x002fff, 0x003040, 0x003040, 0x003097, 0x003098, 0x003100, 0x003104, 0x003130, 0x003130, 0x00318f, 0x00318f, - 0x0031e4, 0x0031ef, 0x00321f, 0x00321f, 0x009ffd, 0x009fff, 0x00a48d, 0x00a48f, 0x00a4c7, 0x00a4cf, 0x00a62c, 0x00a63f, 0x00a6f8, 0x00a6ff, 0x00a7c0, 0x00a7c1, 0x00a7cb, - 0x00a7f4, 0x00a82d, 0x00a82f, 0x00a83a, 0x00a83f, 0x00a878, 0x00a87f, 0x00a8c6, 0x00a8cd, 0x00a8da, 0x00a8df, 0x00a954, 0x00a95e, 0x00a97d, 0x00a97f, 0x00a9ce, 0x00a9ce, - 0x00a9da, 0x00a9dd, 0x00a9ff, 0x00a9ff, 0x00aa37, 0x00aa3f, 0x00aa4e, 0x00aa4f, 0x00aa5a, 0x00aa5b, 0x00aac3, 0x00aada, 0x00aaf7, 0x00ab00, 0x00ab07, 0x00ab08, 0x00ab0f, - 0x00ab10, 0x00ab17, 0x00ab1f, 0x00ab27, 0x00ab27, 0x00ab2f, 0x00ab2f, 0x00ab6c, 0x00ab6f, 0x00abee, 0x00abef, 0x00abfa, 0x00abff, 0x00d7a4, 0x00d7af, 0x00d7c7, 0x00d7ca, - 0x00d7fc, 0x00f8ff, 0x00fa6e, 0x00fa6f, 0x00fada, 0x00faff, 0x00fb07, 0x00fb12, 0x00fb18, 0x00fb1c, 0x00fb37, 0x00fb37, 0x00fb3d, 0x00fb3d, 0x00fb3f, 0x00fb3f, 0x00fb42, - 0x00fb42, 0x00fb45, 0x00fb45, 0x00fbc2, 0x00fbd2, 0x00fd40, 0x00fd4f, 0x00fd90, 0x00fd91, 0x00fdc8, 0x00fdef, 0x00fdfe, 0x00fdff, 0x00fe1a, 0x00fe1f, 0x00fe53, 0x00fe53, - 0x00fe67, 0x00fe67, 0x00fe6c, 0x00fe6f, 0x00fe75, 0x00fe75, 0x00fefd, 0x00ff00, 0x00ffbf, 0x00ffc1, 0x00ffc8, 0x00ffc9, 0x00ffd0, 0x00ffd1, 0x00ffd8, 0x00ffd9, 0x00ffdd, - 0x00ffdf, 0x00ffe7, 0x00ffe7, 0x00ffef, 0x00fffb, 0x00fffe, 0x00ffff, 0x01000c, 0x01000c, 0x010027, 0x010027, 0x01003b, 0x01003b, 0x01003e, 0x01003e, 0x01004e, 0x01004f, - 0x01005e, 0x01007f, 0x0100fb, 0x0100ff, 0x010103, 0x010106, 0x010134, 0x010136, 0x01018f, 0x01018f, 0x01019d, 0x01019f, 0x0101a1, 0x0101cf, 0x0101fe, 0x01027f, 0x01029d, - 0x01029f, 0x0102d1, 0x0102df, 0x0102fc, 0x0102ff, 0x010324, 0x01032c, 0x01034b, 0x01034f, 0x01037b, 0x01037f, 0x01039e, 0x01039e, 0x0103c4, 0x0103c7, 0x0103d6, 0x0103ff, - 0x01049e, 0x01049f, 0x0104aa, 0x0104af, 0x0104d4, 0x0104d7, 0x0104fc, 0x0104ff, 0x010528, 0x01052f, 0x010564, 0x01056e, 0x010570, 0x0105ff, 0x010737, 0x01073f, 0x010756, - 0x01075f, 0x010768, 0x0107ff, 0x010806, 0x010807, 0x010809, 0x010809, 0x010836, 0x010836, 0x010839, 0x01083b, 0x01083d, 0x01083e, 0x010856, 0x010856, 0x01089f, 0x0108a6, - 0x0108b0, 0x0108df, 0x0108f3, 0x0108f3, 0x0108f6, 0x0108fa, 0x01091c, 0x01091e, 0x01093a, 0x01093e, 0x010940, 0x01097f, 0x0109b8, 0x0109bb, 0x0109d0, 0x0109d1, 0x010a04, - 0x010a04, 0x010a07, 0x010a0b, 0x010a14, 0x010a14, 0x010a18, 0x010a18, 0x010a36, 0x010a37, 0x010a3b, 0x010a3e, 0x010a49, 0x010a4f, 0x010a59, 0x010a5f, 0x010aa0, 0x010abf, - 0x010ae7, 0x010aea, 0x010af7, 0x010aff, 0x010b36, 0x010b38, 0x010b56, 0x010b57, 0x010b73, 0x010b77, 0x010b92, 0x010b98, 0x010b9d, 0x010ba8, 0x010bb0, 0x010bff, 0x010c49, - 0x010c7f, 0x010cb3, 0x010cbf, 0x010cf3, 0x010cf9, 0x010d28, 0x010d2f, 0x010d3a, 0x010e5f, 0x010e7f, 0x010e7f, 0x010eaa, 0x010eaa, 0x010eae, 0x010eaf, 0x010eb2, 0x010eff, - 0x010f28, 0x010f2f, 0x010f5a, 0x010faf, 0x010fcc, 0x010fdf, 0x010ff7, 0x010fff, 0x01104e, 0x011051, 0x011070, 0x01107e, 0x0110bd, 0x0110bd, 0x0110c2, 0x0110cf, 0x0110e9, - 0x0110ef, 0x0110fa, 0x0110ff, 0x011135, 0x011135, 0x011148, 0x01114f, 0x011177, 0x01117f, 0x0111e0, 0x0111e0, 0x0111f5, 0x0111ff, 0x011212, 0x011212, 0x01123f, 0x01127f, - 0x011287, 0x011287, 0x011289, 0x011289, 0x01128e, 0x01128e, 0x01129e, 0x01129e, 0x0112aa, 0x0112af, 0x0112eb, 0x0112ef, 0x0112fa, 0x0112ff, 0x011304, 0x011304, 0x01130d, - 0x01130e, 0x011311, 0x011312, 0x011329, 0x011329, 0x011331, 0x011331, 0x011334, 0x011334, 0x01133a, 0x01133a, 0x011345, 0x011346, 0x011349, 0x01134a, 0x01134e, 0x01134f, - 0x011351, 0x011356, 0x011358, 0x01135c, 0x011364, 0x011365, 0x01136d, 0x01136f, 0x011375, 0x0113ff, 0x01145c, 0x01145c, 0x011462, 0x01147f, 0x0114c8, 0x0114cf, 0x0114da, - 0x01157f, 0x0115b6, 0x0115b7, 0x0115de, 0x0115ff, 0x011645, 0x01164f, 0x01165a, 0x01165f, 0x01166d, 0x01167f, 0x0116b9, 0x0116bf, 0x0116ca, 0x0116ff, 0x01171b, 0x01171c, - 0x01172c, 0x01172f, 0x011740, 0x0117ff, 0x01183c, 0x01189f, 0x0118f3, 0x0118fe, 0x011907, 0x011908, 0x01190a, 0x01190b, 0x011914, 0x011914, 0x011917, 0x011917, 0x011936, - 0x011936, 0x011939, 0x01193a, 0x011947, 0x01194f, 0x01195a, 0x01199f, 0x0119a8, 0x0119a9, 0x0119d8, 0x0119d9, 0x0119e5, 0x0119ff, 0x011a48, 0x011a4f, 0x011aa3, 0x011abf, - 0x011af9, 0x011bff, 0x011c09, 0x011c09, 0x011c37, 0x011c37, 0x011c46, 0x011c4f, 0x011c6d, 0x011c6f, 0x011c90, 0x011c91, 0x011ca8, 0x011ca8, 0x011cb7, 0x011cff, 0x011d07, - 0x011d07, 0x011d0a, 0x011d0a, 0x011d37, 0x011d39, 0x011d3b, 0x011d3b, 0x011d3e, 0x011d3e, 0x011d48, 0x011d4f, 0x011d5a, 0x011d5f, 0x011d66, 0x011d66, 0x011d69, 0x011d69, - 0x011d8f, 0x011d8f, 0x011d92, 0x011d92, 0x011d99, 0x011d9f, 0x011daa, 0x011edf, 0x011ef9, 0x011faf, 0x011fb1, 0x011fbf, 0x011ff2, 0x011ffe, 0x01239a, 0x0123ff, 0x01246f, - 0x01246f, 0x012475, 0x01247f, 0x012544, 0x012fff, 0x01342f, 0x0143ff, 0x014647, 0x0167ff, 0x016a39, 0x016a3f, 0x016a5f, 0x016a5f, 0x016a6a, 0x016a6d, 0x016a70, 0x016acf, - 0x016aee, 0x016aef, 0x016af6, 0x016aff, 0x016b46, 0x016b4f, 0x016b5a, 0x016b5a, 0x016b62, 0x016b62, 0x016b78, 0x016b7c, 0x016b90, 0x016e3f, 0x016e9b, 0x016eff, 0x016f4b, - 0x016f4e, 0x016f88, 0x016f8e, 0x016fa0, 0x016fdf, 0x016fe5, 0x016fef, 0x016ff2, 0x016fff, 0x0187f8, 0x0187ff, 0x018cd6, 0x018cff, 0x018d09, 0x01afff, 0x01b11f, 0x01b14f, - 0x01b153, 0x01b163, 0x01b168, 0x01b16f, 0x01b2fc, 0x01bbff, 0x01bc6b, 0x01bc6f, 0x01bc7d, 0x01bc7f, 0x01bc89, 0x01bc8f, 0x01bc9a, 0x01bc9b, 0x01bca0, 0x01cfff, 0x01d0f6, - 0x01d0ff, 0x01d127, 0x01d128, 0x01d173, 0x01d17a, 0x01d1e9, 0x01d1ff, 0x01d246, 0x01d2df, 0x01d2f4, 0x01d2ff, 0x01d357, 0x01d35f, 0x01d379, 0x01d3ff, 0x01d455, 0x01d455, - 0x01d49d, 0x01d49d, 0x01d4a0, 0x01d4a1, 0x01d4a3, 0x01d4a4, 0x01d4a7, 0x01d4a8, 0x01d4ad, 0x01d4ad, 0x01d4ba, 0x01d4ba, 0x01d4bc, 0x01d4bc, 0x01d4c4, 0x01d4c4, 0x01d506, - 0x01d506, 0x01d50b, 0x01d50c, 0x01d515, 0x01d515, 0x01d51d, 0x01d51d, 0x01d53a, 0x01d53a, 0x01d53f, 0x01d53f, 0x01d545, 0x01d545, 0x01d547, 0x01d549, 0x01d551, 0x01d551, - 0x01d6a6, 0x01d6a7, 0x01d7cc, 0x01d7cd, 0x01da8c, 0x01da9a, 0x01daa0, 0x01daa0, 0x01dab0, 0x01dfff, 0x01e007, 0x01e007, 0x01e019, 0x01e01a, 0x01e022, 0x01e022, 0x01e025, - 0x01e025, 0x01e02b, 0x01e0ff, 0x01e12d, 0x01e12f, 0x01e13e, 0x01e13f, 0x01e14a, 0x01e14d, 0x01e150, 0x01e2bf, 0x01e2fa, 0x01e2fe, 0x01e300, 0x01e7ff, 0x01e8c5, 0x01e8c6, - 0x01e8d7, 0x01e8ff, 0x01e94c, 0x01e94f, 0x01e95a, 0x01e95d, 0x01e960, 0x01ec70, 0x01ecb5, 0x01ed00, 0x01ed3e, 0x01edff, 0x01ee04, 0x01ee04, 0x01ee20, 0x01ee20, 0x01ee23, - 0x01ee23, 0x01ee25, 0x01ee26, 0x01ee28, 0x01ee28, 0x01ee33, 0x01ee33, 0x01ee38, 0x01ee38, 0x01ee3a, 0x01ee3a, 0x01ee3c, 0x01ee41, 0x01ee43, 0x01ee46, 0x01ee48, 0x01ee48, - 0x01ee4a, 0x01ee4a, 0x01ee4c, 0x01ee4c, 0x01ee50, 0x01ee50, 0x01ee53, 0x01ee53, 0x01ee55, 0x01ee56, 0x01ee58, 0x01ee58, 0x01ee5a, 0x01ee5a, 0x01ee5c, 0x01ee5c, 0x01ee5e, - 0x01ee5e, 0x01ee60, 0x01ee60, 0x01ee63, 0x01ee63, 0x01ee65, 0x01ee66, 0x01ee6b, 0x01ee6b, 0x01ee73, 0x01ee73, 0x01ee78, 0x01ee78, 0x01ee7d, 0x01ee7d, 0x01ee7f, 0x01ee7f, - 0x01ee8a, 0x01ee8a, 0x01ee9c, 0x01eea0, 0x01eea4, 0x01eea4, 0x01eeaa, 0x01eeaa, 0x01eebc, 0x01eeef, 0x01eef2, 0x01efff, 0x01f02c, 0x01f02f, 0x01f094, 0x01f09f, 0x01f0af, - 0x01f0b0, 0x01f0c0, 0x01f0c0, 0x01f0d0, 0x01f0d0, 0x01f0f6, 0x01f0ff, 0x01f1ae, 0x01f1e5, 0x01f203, 0x01f20f, 0x01f23c, 0x01f23f, 0x01f249, 0x01f24f, 0x01f252, 0x01f25f, - 0x01f266, 0x01f2ff, 0x01f6d8, 0x01f6df, 0x01f6ed, 0x01f6ef, 0x01f6fd, 0x01f6ff, 0x01f774, 0x01f77f, 0x01f7d9, 0x01f7df, 0x01f7ec, 0x01f7ff, 0x01f80c, 0x01f80f, 0x01f848, - 0x01f84f, 0x01f85a, 0x01f85f, 0x01f888, 0x01f88f, 0x01f8ae, 0x01f8af, 0x01f8b2, 0x01f8ff, 0x01f979, 0x01f979, 0x01f9cc, 0x01f9cc, 0x01fa54, 0x01fa5f, 0x01fa6e, 0x01fa6f, - 0x01fa75, 0x01fa77, 0x01fa7b, 0x01fa7f, 0x01fa87, 0x01fa8f, 0x01faa9, 0x01faaf, 0x01fab7, 0x01fabf, 0x01fac3, 0x01facf, 0x01fad7, 0x01faff, 0x01fb93, 0x01fb93, 0x01fbcb, - 0x01fbef, 0x01fbfa, 0x01ffff, 0x02a6de, 0x02a6ff, 0x02b735, 0x02b73f, 0x02b81e, 0x02b81f, 0x02cea2, 0x02ceaf, 0x02ebe1, 0x02f7ff, 0x02fa1e, 0x02ffff, 0x03134b, 0x0e00ff, - 0x0e01f0, 0x10ffff)); + 0x00139a, 0x00139f, 0x0013f6, 0x0013f7, 0x0013fe, 0x0013ff, 0x00169d, 0x00169f, 0x0016f9, 0x0016ff, 0x001716, 0x00171e, 0x001737, 0x00173f, 0x001754, 0x00175f, 0x00176d, + 0x00176d, 0x001771, 0x001771, 0x001774, 0x00177f, 0x0017de, 0x0017df, 0x0017ea, 0x0017ef, 0x0017fa, 0x0017ff, 0x00180e, 0x00180e, 0x00181a, 0x00181f, 0x001879, 0x00187f, + 0x0018ab, 0x0018af, 0x0018f6, 0x0018ff, 0x00191f, 0x00191f, 0x00192c, 0x00192f, 0x00193c, 0x00193f, 0x001941, 0x001943, 0x00196e, 0x00196f, 0x001975, 0x00197f, 0x0019ac, + 0x0019af, 0x0019ca, 0x0019cf, 0x0019db, 0x0019dd, 0x001a1c, 0x001a1d, 0x001a5f, 0x001a5f, 0x001a7d, 0x001a7e, 0x001a8a, 0x001a8f, 0x001a9a, 0x001a9f, 0x001aae, 0x001aaf, + 0x001acf, 0x001aff, 0x001b4d, 0x001b4f, 0x001b7f, 0x001b7f, 0x001bf4, 0x001bfb, 0x001c38, 0x001c3a, 0x001c4a, 0x001c4c, 0x001c89, 0x001c8f, 0x001cbb, 0x001cbc, 0x001cc8, + 0x001ccf, 0x001cfb, 0x001cff, 0x001f16, 0x001f17, 0x001f1e, 0x001f1f, 0x001f46, 0x001f47, 0x001f4e, 0x001f4f, 0x001f58, 0x001f58, 0x001f5a, 0x001f5a, 0x001f5c, 0x001f5c, + 0x001f5e, 0x001f5e, 0x001f7e, 0x001f7f, 0x001fb5, 0x001fb5, 0x001fc5, 0x001fc5, 0x001fd4, 0x001fd5, 0x001fdc, 0x001fdc, 0x001ff0, 0x001ff1, 0x001ff5, 0x001ff5, 0x001fff, + 0x001fff, 0x00200b, 0x00200f, 0x00202a, 0x00202e, 0x002060, 0x00206f, 0x002072, 0x002073, 0x00208f, 0x00208f, 0x00209d, 0x00209f, 0x0020c1, 0x0020cf, 0x0020f1, 0x0020ff, + 0x00218c, 0x00218f, 0x002427, 0x00243f, 0x00244b, 0x00245f, 0x002b74, 0x002b75, 0x002b96, 0x002b96, 0x002cf4, 0x002cf8, 0x002d26, 0x002d26, 0x002d28, 0x002d2c, 0x002d2e, + 0x002d2f, 0x002d68, 0x002d6e, 0x002d71, 0x002d7e, 0x002d97, 0x002d9f, 0x002da7, 0x002da7, 0x002daf, 0x002daf, 0x002db7, 0x002db7, 0x002dbf, 0x002dbf, 0x002dc7, 0x002dc7, + 0x002dcf, 0x002dcf, 0x002dd7, 0x002dd7, 0x002ddf, 0x002ddf, 0x002e5e, 0x002e7f, 0x002e9a, 0x002e9a, 0x002ef4, 0x002eff, 0x002fd6, 0x002fef, 0x002ffc, 0x002fff, 0x003040, + 0x003040, 0x003097, 0x003098, 0x003100, 0x003104, 0x003130, 0x003130, 0x00318f, 0x00318f, 0x0031e4, 0x0031ef, 0x00321f, 0x00321f, 0x00a48d, 0x00a48f, 0x00a4c7, 0x00a4cf, + 0x00a62c, 0x00a63f, 0x00a6f8, 0x00a6ff, 0x00a7cb, 0x00a7cf, 0x00a7d2, 0x00a7d2, 0x00a7d4, 0x00a7d4, 0x00a7da, 0x00a7f1, 0x00a82d, 0x00a82f, 0x00a83a, 0x00a83f, 0x00a878, + 0x00a87f, 0x00a8c6, 0x00a8cd, 0x00a8da, 0x00a8df, 0x00a954, 0x00a95e, 0x00a97d, 0x00a97f, 0x00a9ce, 0x00a9ce, 0x00a9da, 0x00a9dd, 0x00a9ff, 0x00a9ff, 0x00aa37, 0x00aa3f, + 0x00aa4e, 0x00aa4f, 0x00aa5a, 0x00aa5b, 0x00aac3, 0x00aada, 0x00aaf7, 0x00ab00, 0x00ab07, 0x00ab08, 0x00ab0f, 0x00ab10, 0x00ab17, 0x00ab1f, 0x00ab27, 0x00ab27, 0x00ab2f, + 0x00ab2f, 0x00ab6c, 0x00ab6f, 0x00abee, 0x00abef, 0x00abfa, 0x00abff, 0x00d7a4, 0x00d7af, 0x00d7c7, 0x00d7ca, 0x00d7fc, 0x00f8ff, 0x00fa6e, 0x00fa6f, 0x00fada, 0x00faff, + 0x00fb07, 0x00fb12, 0x00fb18, 0x00fb1c, 0x00fb37, 0x00fb37, 0x00fb3d, 0x00fb3d, 0x00fb3f, 0x00fb3f, 0x00fb42, 0x00fb42, 0x00fb45, 0x00fb45, 0x00fbc3, 0x00fbd2, 0x00fd90, + 0x00fd91, 0x00fdc8, 0x00fdce, 0x00fdd0, 0x00fdef, 0x00fe1a, 0x00fe1f, 0x00fe53, 0x00fe53, 0x00fe67, 0x00fe67, 0x00fe6c, 0x00fe6f, 0x00fe75, 0x00fe75, 0x00fefd, 0x00ff00, + 0x00ffbf, 0x00ffc1, 0x00ffc8, 0x00ffc9, 0x00ffd0, 0x00ffd1, 0x00ffd8, 0x00ffd9, 0x00ffdd, 0x00ffdf, 0x00ffe7, 0x00ffe7, 0x00ffef, 0x00fffb, 0x00fffe, 0x00ffff, 0x01000c, + 0x01000c, 0x010027, 0x010027, 0x01003b, 0x01003b, 0x01003e, 0x01003e, 0x01004e, 0x01004f, 0x01005e, 0x01007f, 0x0100fb, 0x0100ff, 0x010103, 0x010106, 0x010134, 0x010136, + 0x01018f, 0x01018f, 0x01019d, 0x01019f, 0x0101a1, 0x0101cf, 0x0101fe, 0x01027f, 0x01029d, 0x01029f, 0x0102d1, 0x0102df, 0x0102fc, 0x0102ff, 0x010324, 0x01032c, 0x01034b, + 0x01034f, 0x01037b, 0x01037f, 0x01039e, 0x01039e, 0x0103c4, 0x0103c7, 0x0103d6, 0x0103ff, 0x01049e, 0x01049f, 0x0104aa, 0x0104af, 0x0104d4, 0x0104d7, 0x0104fc, 0x0104ff, + 0x010528, 0x01052f, 0x010564, 0x01056e, 0x01057b, 0x01057b, 0x01058b, 0x01058b, 0x010593, 0x010593, 0x010596, 0x010596, 0x0105a2, 0x0105a2, 0x0105b2, 0x0105b2, 0x0105ba, + 0x0105ba, 0x0105bd, 0x0105ff, 0x010737, 0x01073f, 0x010756, 0x01075f, 0x010768, 0x01077f, 0x010786, 0x010786, 0x0107b1, 0x0107b1, 0x0107bb, 0x0107ff, 0x010806, 0x010807, + 0x010809, 0x010809, 0x010836, 0x010836, 0x010839, 0x01083b, 0x01083d, 0x01083e, 0x010856, 0x010856, 0x01089f, 0x0108a6, 0x0108b0, 0x0108df, 0x0108f3, 0x0108f3, 0x0108f6, + 0x0108fa, 0x01091c, 0x01091e, 0x01093a, 0x01093e, 0x010940, 0x01097f, 0x0109b8, 0x0109bb, 0x0109d0, 0x0109d1, 0x010a04, 0x010a04, 0x010a07, 0x010a0b, 0x010a14, 0x010a14, + 0x010a18, 0x010a18, 0x010a36, 0x010a37, 0x010a3b, 0x010a3e, 0x010a49, 0x010a4f, 0x010a59, 0x010a5f, 0x010aa0, 0x010abf, 0x010ae7, 0x010aea, 0x010af7, 0x010aff, 0x010b36, + 0x010b38, 0x010b56, 0x010b57, 0x010b73, 0x010b77, 0x010b92, 0x010b98, 0x010b9d, 0x010ba8, 0x010bb0, 0x010bff, 0x010c49, 0x010c7f, 0x010cb3, 0x010cbf, 0x010cf3, 0x010cf9, + 0x010d28, 0x010d2f, 0x010d3a, 0x010e5f, 0x010e7f, 0x010e7f, 0x010eaa, 0x010eaa, 0x010eae, 0x010eaf, 0x010eb2, 0x010eff, 0x010f28, 0x010f2f, 0x010f5a, 0x010f6f, 0x010f8a, + 0x010faf, 0x010fcc, 0x010fdf, 0x010ff7, 0x010fff, 0x01104e, 0x011051, 0x011076, 0x01107e, 0x0110bd, 0x0110bd, 0x0110c3, 0x0110cf, 0x0110e9, 0x0110ef, 0x0110fa, 0x0110ff, + 0x011135, 0x011135, 0x011148, 0x01114f, 0x011177, 0x01117f, 0x0111e0, 0x0111e0, 0x0111f5, 0x0111ff, 0x011212, 0x011212, 0x01123f, 0x01127f, 0x011287, 0x011287, 0x011289, + 0x011289, 0x01128e, 0x01128e, 0x01129e, 0x01129e, 0x0112aa, 0x0112af, 0x0112eb, 0x0112ef, 0x0112fa, 0x0112ff, 0x011304, 0x011304, 0x01130d, 0x01130e, 0x011311, 0x011312, + 0x011329, 0x011329, 0x011331, 0x011331, 0x011334, 0x011334, 0x01133a, 0x01133a, 0x011345, 0x011346, 0x011349, 0x01134a, 0x01134e, 0x01134f, 0x011351, 0x011356, 0x011358, + 0x01135c, 0x011364, 0x011365, 0x01136d, 0x01136f, 0x011375, 0x0113ff, 0x01145c, 0x01145c, 0x011462, 0x01147f, 0x0114c8, 0x0114cf, 0x0114da, 0x01157f, 0x0115b6, 0x0115b7, + 0x0115de, 0x0115ff, 0x011645, 0x01164f, 0x01165a, 0x01165f, 0x01166d, 0x01167f, 0x0116ba, 0x0116bf, 0x0116ca, 0x0116ff, 0x01171b, 0x01171c, 0x01172c, 0x01172f, 0x011747, + 0x0117ff, 0x01183c, 0x01189f, 0x0118f3, 0x0118fe, 0x011907, 0x011908, 0x01190a, 0x01190b, 0x011914, 0x011914, 0x011917, 0x011917, 0x011936, 0x011936, 0x011939, 0x01193a, + 0x011947, 0x01194f, 0x01195a, 0x01199f, 0x0119a8, 0x0119a9, 0x0119d8, 0x0119d9, 0x0119e5, 0x0119ff, 0x011a48, 0x011a4f, 0x011aa3, 0x011aaf, 0x011af9, 0x011bff, 0x011c09, + 0x011c09, 0x011c37, 0x011c37, 0x011c46, 0x011c4f, 0x011c6d, 0x011c6f, 0x011c90, 0x011c91, 0x011ca8, 0x011ca8, 0x011cb7, 0x011cff, 0x011d07, 0x011d07, 0x011d0a, 0x011d0a, + 0x011d37, 0x011d39, 0x011d3b, 0x011d3b, 0x011d3e, 0x011d3e, 0x011d48, 0x011d4f, 0x011d5a, 0x011d5f, 0x011d66, 0x011d66, 0x011d69, 0x011d69, 0x011d8f, 0x011d8f, 0x011d92, + 0x011d92, 0x011d99, 0x011d9f, 0x011daa, 0x011edf, 0x011ef9, 0x011faf, 0x011fb1, 0x011fbf, 0x011ff2, 0x011ffe, 0x01239a, 0x0123ff, 0x01246f, 0x01246f, 0x012475, 0x01247f, + 0x012544, 0x012f8f, 0x012ff3, 0x012fff, 0x01342f, 0x0143ff, 0x014647, 0x0167ff, 0x016a39, 0x016a3f, 0x016a5f, 0x016a5f, 0x016a6a, 0x016a6d, 0x016abf, 0x016abf, 0x016aca, + 0x016acf, 0x016aee, 0x016aef, 0x016af6, 0x016aff, 0x016b46, 0x016b4f, 0x016b5a, 0x016b5a, 0x016b62, 0x016b62, 0x016b78, 0x016b7c, 0x016b90, 0x016e3f, 0x016e9b, 0x016eff, + 0x016f4b, 0x016f4e, 0x016f88, 0x016f8e, 0x016fa0, 0x016fdf, 0x016fe5, 0x016fef, 0x016ff2, 0x016fff, 0x0187f8, 0x0187ff, 0x018cd6, 0x018cff, 0x018d09, 0x01afef, 0x01aff4, + 0x01aff4, 0x01affc, 0x01affc, 0x01afff, 0x01afff, 0x01b123, 0x01b14f, 0x01b153, 0x01b163, 0x01b168, 0x01b16f, 0x01b2fc, 0x01bbff, 0x01bc6b, 0x01bc6f, 0x01bc7d, 0x01bc7f, + 0x01bc89, 0x01bc8f, 0x01bc9a, 0x01bc9b, 0x01bca0, 0x01ceff, 0x01cf2e, 0x01cf2f, 0x01cf47, 0x01cf4f, 0x01cfc4, 0x01cfff, 0x01d0f6, 0x01d0ff, 0x01d127, 0x01d128, 0x01d173, + 0x01d17a, 0x01d1eb, 0x01d1ff, 0x01d246, 0x01d2df, 0x01d2f4, 0x01d2ff, 0x01d357, 0x01d35f, 0x01d379, 0x01d3ff, 0x01d455, 0x01d455, 0x01d49d, 0x01d49d, 0x01d4a0, 0x01d4a1, + 0x01d4a3, 0x01d4a4, 0x01d4a7, 0x01d4a8, 0x01d4ad, 0x01d4ad, 0x01d4ba, 0x01d4ba, 0x01d4bc, 0x01d4bc, 0x01d4c4, 0x01d4c4, 0x01d506, 0x01d506, 0x01d50b, 0x01d50c, 0x01d515, + 0x01d515, 0x01d51d, 0x01d51d, 0x01d53a, 0x01d53a, 0x01d53f, 0x01d53f, 0x01d545, 0x01d545, 0x01d547, 0x01d549, 0x01d551, 0x01d551, 0x01d6a6, 0x01d6a7, 0x01d7cc, 0x01d7cd, + 0x01da8c, 0x01da9a, 0x01daa0, 0x01daa0, 0x01dab0, 0x01deff, 0x01df1f, 0x01dfff, 0x01e007, 0x01e007, 0x01e019, 0x01e01a, 0x01e022, 0x01e022, 0x01e025, 0x01e025, 0x01e02b, + 0x01e0ff, 0x01e12d, 0x01e12f, 0x01e13e, 0x01e13f, 0x01e14a, 0x01e14d, 0x01e150, 0x01e28f, 0x01e2af, 0x01e2bf, 0x01e2fa, 0x01e2fe, 0x01e300, 0x01e7df, 0x01e7e7, 0x01e7e7, + 0x01e7ec, 0x01e7ec, 0x01e7ef, 0x01e7ef, 0x01e7ff, 0x01e7ff, 0x01e8c5, 0x01e8c6, 0x01e8d7, 0x01e8ff, 0x01e94c, 0x01e94f, 0x01e95a, 0x01e95d, 0x01e960, 0x01ec70, 0x01ecb5, + 0x01ed00, 0x01ed3e, 0x01edff, 0x01ee04, 0x01ee04, 0x01ee20, 0x01ee20, 0x01ee23, 0x01ee23, 0x01ee25, 0x01ee26, 0x01ee28, 0x01ee28, 0x01ee33, 0x01ee33, 0x01ee38, 0x01ee38, + 0x01ee3a, 0x01ee3a, 0x01ee3c, 0x01ee41, 0x01ee43, 0x01ee46, 0x01ee48, 0x01ee48, 0x01ee4a, 0x01ee4a, 0x01ee4c, 0x01ee4c, 0x01ee50, 0x01ee50, 0x01ee53, 0x01ee53, 0x01ee55, + 0x01ee56, 0x01ee58, 0x01ee58, 0x01ee5a, 0x01ee5a, 0x01ee5c, 0x01ee5c, 0x01ee5e, 0x01ee5e, 0x01ee60, 0x01ee60, 0x01ee63, 0x01ee63, 0x01ee65, 0x01ee66, 0x01ee6b, 0x01ee6b, + 0x01ee73, 0x01ee73, 0x01ee78, 0x01ee78, 0x01ee7d, 0x01ee7d, 0x01ee7f, 0x01ee7f, 0x01ee8a, 0x01ee8a, 0x01ee9c, 0x01eea0, 0x01eea4, 0x01eea4, 0x01eeaa, 0x01eeaa, 0x01eebc, + 0x01eeef, 0x01eef2, 0x01efff, 0x01f02c, 0x01f02f, 0x01f094, 0x01f09f, 0x01f0af, 0x01f0b0, 0x01f0c0, 0x01f0c0, 0x01f0d0, 0x01f0d0, 0x01f0f6, 0x01f0ff, 0x01f1ae, 0x01f1e5, + 0x01f203, 0x01f20f, 0x01f23c, 0x01f23f, 0x01f249, 0x01f24f, 0x01f252, 0x01f25f, 0x01f266, 0x01f2ff, 0x01f6d8, 0x01f6dc, 0x01f6ed, 0x01f6ef, 0x01f6fd, 0x01f6ff, 0x01f774, + 0x01f77f, 0x01f7d9, 0x01f7df, 0x01f7ec, 0x01f7ef, 0x01f7f1, 0x01f7ff, 0x01f80c, 0x01f80f, 0x01f848, 0x01f84f, 0x01f85a, 0x01f85f, 0x01f888, 0x01f88f, 0x01f8ae, 0x01f8af, + 0x01f8b2, 0x01f8ff, 0x01fa54, 0x01fa5f, 0x01fa6e, 0x01fa6f, 0x01fa75, 0x01fa77, 0x01fa7d, 0x01fa7f, 0x01fa87, 0x01fa8f, 0x01faad, 0x01faaf, 0x01fabb, 0x01fabf, 0x01fac6, + 0x01facf, 0x01fada, 0x01fadf, 0x01fae8, 0x01faef, 0x01faf7, 0x01faff, 0x01fb93, 0x01fb93, 0x01fbcb, 0x01fbef, 0x01fbfa, 0x01ffff, 0x02a6e0, 0x02a6ff, 0x02b739, 0x02b73f, + 0x02b81e, 0x02b81f, 0x02cea2, 0x02ceaf, 0x02ebe1, 0x02f7ff, 0x02fa1e, 0x02ffff, 0x03134b, 0x0e00ff, 0x0e01f0, 0x10ffff)); } } diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/charset/UnicodePropertyData.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/charset/UnicodePropertyData.java index 79af63ece906..25c8a8c4fffd 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/charset/UnicodePropertyData.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/charset/UnicodePropertyData.java @@ -47,18 +47,15 @@ import org.graalvm.collections.EconomicMap; -import com.oracle.truffle.api.CompilerDirectives; - class UnicodePropertyData { static final EconomicMap PROPERTY_ALIASES = EconomicMap.create(105); static final EconomicMap GENERAL_CATEGORY_ALIASES = EconomicMap.create(80); - static final EconomicMap SCRIPT_ALIASES = EconomicMap.create(312); - private static final EconomicMap SET_ENCODINGS = EconomicMap.create(397); + static final EconomicMap SCRIPT_ALIASES = EconomicMap.create(321); + private static final EconomicMap SET_ENCODINGS = EconomicMap.create(407); public static CodePointSet retrieveProperty(String propertySpec) { if (!SET_ENCODINGS.containsKey(propertySpec)) { - CompilerDirectives.transferToInterpreterAndInvalidate(); throw new IllegalArgumentException("Unsupported Unicode character property escape"); } return SET_ENCODINGS.get(propertySpec); @@ -301,9 +298,11 @@ public static CodePointSet retrieveProperty(String propertySpec) { SCRIPT_ALIASES.put("Common", "Zyyy"); SCRIPT_ALIASES.put("Copt", "Copt"); SCRIPT_ALIASES.put("Coptic", "Copt"); + SCRIPT_ALIASES.put("Cpmn", "Cpmn"); SCRIPT_ALIASES.put("Cprt", "Cprt"); SCRIPT_ALIASES.put("Cuneiform", "Xsux"); SCRIPT_ALIASES.put("Cypriot", "Cprt"); + SCRIPT_ALIASES.put("Cypro_Minoan", "Cpmn"); SCRIPT_ALIASES.put("Cyrillic", "Cyrl"); SCRIPT_ALIASES.put("Cyrl", "Cyrl"); SCRIPT_ALIASES.put("Deseret", "Dsrt"); @@ -459,6 +458,7 @@ public static CodePointSet retrieveProperty(String propertySpec) { SCRIPT_ALIASES.put("Old_Sogdian", "Sogo"); SCRIPT_ALIASES.put("Old_South_Arabian", "Sarb"); SCRIPT_ALIASES.put("Old_Turkic", "Orkh"); + SCRIPT_ALIASES.put("Old_Uyghur", "Ougr"); SCRIPT_ALIASES.put("Oriya", "Orya"); SCRIPT_ALIASES.put("Orkh", "Orkh"); SCRIPT_ALIASES.put("Orya", "Orya"); @@ -466,6 +466,7 @@ public static CodePointSet retrieveProperty(String propertySpec) { SCRIPT_ALIASES.put("Osge", "Osge"); SCRIPT_ALIASES.put("Osma", "Osma"); SCRIPT_ALIASES.put("Osmanya", "Osma"); + SCRIPT_ALIASES.put("Ougr", "Ougr"); SCRIPT_ALIASES.put("Pahawh_Hmong", "Hmng"); SCRIPT_ALIASES.put("Palm", "Palm"); SCRIPT_ALIASES.put("Palmyrene", "Palm"); @@ -530,6 +531,7 @@ public static CodePointSet retrieveProperty(String propertySpec) { SCRIPT_ALIASES.put("Tamil", "Taml"); SCRIPT_ALIASES.put("Taml", "Taml"); SCRIPT_ALIASES.put("Tang", "Tang"); + SCRIPT_ALIASES.put("Tangsa", "Tnsa"); SCRIPT_ALIASES.put("Tangut", "Tang"); SCRIPT_ALIASES.put("Tavt", "Tavt"); SCRIPT_ALIASES.put("Telu", "Telu"); @@ -544,11 +546,15 @@ public static CodePointSet retrieveProperty(String propertySpec) { SCRIPT_ALIASES.put("Tifinagh", "Tfng"); SCRIPT_ALIASES.put("Tirh", "Tirh"); SCRIPT_ALIASES.put("Tirhuta", "Tirh"); + SCRIPT_ALIASES.put("Tnsa", "Tnsa"); + SCRIPT_ALIASES.put("Toto", "Toto"); SCRIPT_ALIASES.put("Ugar", "Ugar"); SCRIPT_ALIASES.put("Ugaritic", "Ugar"); SCRIPT_ALIASES.put("Unknown", "Zzzz"); SCRIPT_ALIASES.put("Vai", "Vaii"); SCRIPT_ALIASES.put("Vaii", "Vaii"); + SCRIPT_ALIASES.put("Vith", "Vith"); + SCRIPT_ALIASES.put("Vithkuqi", "Vith"); SCRIPT_ALIASES.put("Wancho", "Wcho"); SCRIPT_ALIASES.put("Wara", "Wara"); SCRIPT_ALIASES.put("Warang_Citi", "Wara"); @@ -673,6 +679,7 @@ public static CodePointSet retrieveProperty(String propertySpec) { populateSC_CHER(); populateSC_CHRS(); populateSC_COPT(); + populateSC_CPMN(); populateSC_CPRT(); populateSC_CYRL(); populateSC_DEVA(); @@ -751,6 +758,7 @@ public static CodePointSet retrieveProperty(String propertySpec) { populateSC_ORYA(); populateSC_OSGE(); populateSC_OSMA(); + populateSC_OUGR(); populateSC_PALM(); populateSC_PAUC(); populateSC_PERM(); @@ -793,8 +801,11 @@ public static CodePointSet retrieveProperty(String propertySpec) { populateSC_THAI(); populateSC_TIBT(); populateSC_TIRH(); + populateSC_TNSA(); + populateSC_TOTO(); populateSC_UGAR(); populateSC_VAII(); + populateSC_VITH(); populateSC_WARA(); populateSC_WCHO(); populateSC_XPEO(); @@ -830,6 +841,7 @@ public static CodePointSet retrieveProperty(String propertySpec) { populateSCX_CHER(); populateSCX_CHRS(); populateSCX_COPT(); + populateSCX_CPMN(); populateSCX_CPRT(); populateSCX_CYRL(); populateSCX_DEVA(); @@ -908,6 +920,7 @@ public static CodePointSet retrieveProperty(String propertySpec) { populateSCX_ORYA(); populateSCX_OSGE(); populateSCX_OSMA(); + populateSCX_OUGR(); populateSCX_PALM(); populateSCX_PAUC(); populateSCX_PERM(); @@ -950,8 +963,11 @@ public static CodePointSet retrieveProperty(String propertySpec) { populateSCX_THAI(); populateSCX_TIBT(); populateSCX_TIRH(); + populateSCX_TNSA(); + populateSCX_TOTO(); populateSCX_UGAR(); populateSCX_VAII(); + populateSCX_VITH(); populateSCX_WARA(); populateSCX_WCHO(); populateSCX_XPEO(); @@ -979,82 +995,86 @@ private static void populateALPHA() { 0x00052f, 0x000531, 0x000556, 0x000559, 0x000559, 0x000560, 0x000588, 0x0005b0, 0x0005bd, 0x0005bf, 0x0005bf, 0x0005c1, 0x0005c2, 0x0005c4, 0x0005c5, 0x0005c7, 0x0005c7, 0x0005d0, 0x0005ea, 0x0005ef, 0x0005f2, 0x000610, 0x00061a, 0x000620, 0x000657, 0x000659, 0x00065f, 0x00066e, 0x0006d3, 0x0006d5, 0x0006dc, 0x0006e1, 0x0006e8, 0x0006ed, 0x0006ef, 0x0006fa, 0x0006fc, 0x0006ff, 0x0006ff, 0x000710, 0x00073f, 0x00074d, 0x0007b1, 0x0007ca, 0x0007ea, 0x0007f4, 0x0007f5, 0x0007fa, 0x0007fa, 0x000800, 0x000817, - 0x00081a, 0x00082c, 0x000840, 0x000858, 0x000860, 0x00086a, 0x0008a0, 0x0008b4, 0x0008b6, 0x0008c7, 0x0008d4, 0x0008df, 0x0008e3, 0x0008e9, 0x0008f0, 0x00093b, 0x00093d, - 0x00094c, 0x00094e, 0x000950, 0x000955, 0x000963, 0x000971, 0x000983, 0x000985, 0x00098c, 0x00098f, 0x000990, 0x000993, 0x0009a8, 0x0009aa, 0x0009b0, 0x0009b2, 0x0009b2, - 0x0009b6, 0x0009b9, 0x0009bd, 0x0009c4, 0x0009c7, 0x0009c8, 0x0009cb, 0x0009cc, 0x0009ce, 0x0009ce, 0x0009d7, 0x0009d7, 0x0009dc, 0x0009dd, 0x0009df, 0x0009e3, 0x0009f0, - 0x0009f1, 0x0009fc, 0x0009fc, 0x000a01, 0x000a03, 0x000a05, 0x000a0a, 0x000a0f, 0x000a10, 0x000a13, 0x000a28, 0x000a2a, 0x000a30, 0x000a32, 0x000a33, 0x000a35, 0x000a36, - 0x000a38, 0x000a39, 0x000a3e, 0x000a42, 0x000a47, 0x000a48, 0x000a4b, 0x000a4c, 0x000a51, 0x000a51, 0x000a59, 0x000a5c, 0x000a5e, 0x000a5e, 0x000a70, 0x000a75, 0x000a81, - 0x000a83, 0x000a85, 0x000a8d, 0x000a8f, 0x000a91, 0x000a93, 0x000aa8, 0x000aaa, 0x000ab0, 0x000ab2, 0x000ab3, 0x000ab5, 0x000ab9, 0x000abd, 0x000ac5, 0x000ac7, 0x000ac9, - 0x000acb, 0x000acc, 0x000ad0, 0x000ad0, 0x000ae0, 0x000ae3, 0x000af9, 0x000afc, 0x000b01, 0x000b03, 0x000b05, 0x000b0c, 0x000b0f, 0x000b10, 0x000b13, 0x000b28, 0x000b2a, - 0x000b30, 0x000b32, 0x000b33, 0x000b35, 0x000b39, 0x000b3d, 0x000b44, 0x000b47, 0x000b48, 0x000b4b, 0x000b4c, 0x000b56, 0x000b57, 0x000b5c, 0x000b5d, 0x000b5f, 0x000b63, - 0x000b71, 0x000b71, 0x000b82, 0x000b83, 0x000b85, 0x000b8a, 0x000b8e, 0x000b90, 0x000b92, 0x000b95, 0x000b99, 0x000b9a, 0x000b9c, 0x000b9c, 0x000b9e, 0x000b9f, 0x000ba3, - 0x000ba4, 0x000ba8, 0x000baa, 0x000bae, 0x000bb9, 0x000bbe, 0x000bc2, 0x000bc6, 0x000bc8, 0x000bca, 0x000bcc, 0x000bd0, 0x000bd0, 0x000bd7, 0x000bd7, 0x000c00, 0x000c03, - 0x000c05, 0x000c0c, 0x000c0e, 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3d, 0x000c44, 0x000c46, 0x000c48, 0x000c4a, 0x000c4c, 0x000c55, 0x000c56, 0x000c58, - 0x000c5a, 0x000c60, 0x000c63, 0x000c80, 0x000c83, 0x000c85, 0x000c8c, 0x000c8e, 0x000c90, 0x000c92, 0x000ca8, 0x000caa, 0x000cb3, 0x000cb5, 0x000cb9, 0x000cbd, 0x000cc4, - 0x000cc6, 0x000cc8, 0x000cca, 0x000ccc, 0x000cd5, 0x000cd6, 0x000cde, 0x000cde, 0x000ce0, 0x000ce3, 0x000cf1, 0x000cf2, 0x000d00, 0x000d0c, 0x000d0e, 0x000d10, 0x000d12, - 0x000d3a, 0x000d3d, 0x000d44, 0x000d46, 0x000d48, 0x000d4a, 0x000d4c, 0x000d4e, 0x000d4e, 0x000d54, 0x000d57, 0x000d5f, 0x000d63, 0x000d7a, 0x000d7f, 0x000d81, 0x000d83, - 0x000d85, 0x000d96, 0x000d9a, 0x000db1, 0x000db3, 0x000dbb, 0x000dbd, 0x000dbd, 0x000dc0, 0x000dc6, 0x000dcf, 0x000dd4, 0x000dd6, 0x000dd6, 0x000dd8, 0x000ddf, 0x000df2, - 0x000df3, 0x000e01, 0x000e3a, 0x000e40, 0x000e46, 0x000e4d, 0x000e4d, 0x000e81, 0x000e82, 0x000e84, 0x000e84, 0x000e86, 0x000e8a, 0x000e8c, 0x000ea3, 0x000ea5, 0x000ea5, - 0x000ea7, 0x000eb9, 0x000ebb, 0x000ebd, 0x000ec0, 0x000ec4, 0x000ec6, 0x000ec6, 0x000ecd, 0x000ecd, 0x000edc, 0x000edf, 0x000f00, 0x000f00, 0x000f40, 0x000f47, 0x000f49, - 0x000f6c, 0x000f71, 0x000f81, 0x000f88, 0x000f97, 0x000f99, 0x000fbc, 0x001000, 0x001036, 0x001038, 0x001038, 0x00103b, 0x00103f, 0x001050, 0x00108f, 0x00109a, 0x00109d, - 0x0010a0, 0x0010c5, 0x0010c7, 0x0010c7, 0x0010cd, 0x0010cd, 0x0010d0, 0x0010fa, 0x0010fc, 0x001248, 0x00124a, 0x00124d, 0x001250, 0x001256, 0x001258, 0x001258, 0x00125a, - 0x00125d, 0x001260, 0x001288, 0x00128a, 0x00128d, 0x001290, 0x0012b0, 0x0012b2, 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, - 0x0012d8, 0x001310, 0x001312, 0x001315, 0x001318, 0x00135a, 0x001380, 0x00138f, 0x0013a0, 0x0013f5, 0x0013f8, 0x0013fd, 0x001401, 0x00166c, 0x00166f, 0x00167f, 0x001681, - 0x00169a, 0x0016a0, 0x0016ea, 0x0016ee, 0x0016f8, 0x001700, 0x00170c, 0x00170e, 0x001713, 0x001720, 0x001733, 0x001740, 0x001753, 0x001760, 0x00176c, 0x00176e, 0x001770, - 0x001772, 0x001773, 0x001780, 0x0017b3, 0x0017b6, 0x0017c8, 0x0017d7, 0x0017d7, 0x0017dc, 0x0017dc, 0x001820, 0x001878, 0x001880, 0x0018aa, 0x0018b0, 0x0018f5, 0x001900, - 0x00191e, 0x001920, 0x00192b, 0x001930, 0x001938, 0x001950, 0x00196d, 0x001970, 0x001974, 0x001980, 0x0019ab, 0x0019b0, 0x0019c9, 0x001a00, 0x001a1b, 0x001a20, 0x001a5e, - 0x001a61, 0x001a74, 0x001aa7, 0x001aa7, 0x001abf, 0x001ac0, 0x001b00, 0x001b33, 0x001b35, 0x001b43, 0x001b45, 0x001b4b, 0x001b80, 0x001ba9, 0x001bac, 0x001baf, 0x001bba, - 0x001be5, 0x001be7, 0x001bf1, 0x001c00, 0x001c36, 0x001c4d, 0x001c4f, 0x001c5a, 0x001c7d, 0x001c80, 0x001c88, 0x001c90, 0x001cba, 0x001cbd, 0x001cbf, 0x001ce9, 0x001cec, - 0x001cee, 0x001cf3, 0x001cf5, 0x001cf6, 0x001cfa, 0x001cfa, 0x001d00, 0x001dbf, 0x001de7, 0x001df4, 0x001e00, 0x001f15, 0x001f18, 0x001f1d, 0x001f20, 0x001f45, 0x001f48, - 0x001f4d, 0x001f50, 0x001f57, 0x001f59, 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f7d, 0x001f80, 0x001fb4, 0x001fb6, 0x001fbc, 0x001fbe, 0x001fbe, - 0x001fc2, 0x001fc4, 0x001fc6, 0x001fcc, 0x001fd0, 0x001fd3, 0x001fd6, 0x001fdb, 0x001fe0, 0x001fec, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ffc, 0x002071, 0x002071, 0x00207f, - 0x00207f, 0x002090, 0x00209c, 0x002102, 0x002102, 0x002107, 0x002107, 0x00210a, 0x002113, 0x002115, 0x002115, 0x002119, 0x00211d, 0x002124, 0x002124, 0x002126, 0x002126, - 0x002128, 0x002128, 0x00212a, 0x00212d, 0x00212f, 0x002139, 0x00213c, 0x00213f, 0x002145, 0x002149, 0x00214e, 0x00214e, 0x002160, 0x002188, 0x0024b6, 0x0024e9, 0x002c00, - 0x002c2e, 0x002c30, 0x002c5e, 0x002c60, 0x002ce4, 0x002ceb, 0x002cee, 0x002cf2, 0x002cf3, 0x002d00, 0x002d25, 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, 0x002d30, 0x002d67, + 0x00081a, 0x00082c, 0x000840, 0x000858, 0x000860, 0x00086a, 0x000870, 0x000887, 0x000889, 0x00088e, 0x0008a0, 0x0008c9, 0x0008d4, 0x0008df, 0x0008e3, 0x0008e9, 0x0008f0, + 0x00093b, 0x00093d, 0x00094c, 0x00094e, 0x000950, 0x000955, 0x000963, 0x000971, 0x000983, 0x000985, 0x00098c, 0x00098f, 0x000990, 0x000993, 0x0009a8, 0x0009aa, 0x0009b0, + 0x0009b2, 0x0009b2, 0x0009b6, 0x0009b9, 0x0009bd, 0x0009c4, 0x0009c7, 0x0009c8, 0x0009cb, 0x0009cc, 0x0009ce, 0x0009ce, 0x0009d7, 0x0009d7, 0x0009dc, 0x0009dd, 0x0009df, + 0x0009e3, 0x0009f0, 0x0009f1, 0x0009fc, 0x0009fc, 0x000a01, 0x000a03, 0x000a05, 0x000a0a, 0x000a0f, 0x000a10, 0x000a13, 0x000a28, 0x000a2a, 0x000a30, 0x000a32, 0x000a33, + 0x000a35, 0x000a36, 0x000a38, 0x000a39, 0x000a3e, 0x000a42, 0x000a47, 0x000a48, 0x000a4b, 0x000a4c, 0x000a51, 0x000a51, 0x000a59, 0x000a5c, 0x000a5e, 0x000a5e, 0x000a70, + 0x000a75, 0x000a81, 0x000a83, 0x000a85, 0x000a8d, 0x000a8f, 0x000a91, 0x000a93, 0x000aa8, 0x000aaa, 0x000ab0, 0x000ab2, 0x000ab3, 0x000ab5, 0x000ab9, 0x000abd, 0x000ac5, + 0x000ac7, 0x000ac9, 0x000acb, 0x000acc, 0x000ad0, 0x000ad0, 0x000ae0, 0x000ae3, 0x000af9, 0x000afc, 0x000b01, 0x000b03, 0x000b05, 0x000b0c, 0x000b0f, 0x000b10, 0x000b13, + 0x000b28, 0x000b2a, 0x000b30, 0x000b32, 0x000b33, 0x000b35, 0x000b39, 0x000b3d, 0x000b44, 0x000b47, 0x000b48, 0x000b4b, 0x000b4c, 0x000b56, 0x000b57, 0x000b5c, 0x000b5d, + 0x000b5f, 0x000b63, 0x000b71, 0x000b71, 0x000b82, 0x000b83, 0x000b85, 0x000b8a, 0x000b8e, 0x000b90, 0x000b92, 0x000b95, 0x000b99, 0x000b9a, 0x000b9c, 0x000b9c, 0x000b9e, + 0x000b9f, 0x000ba3, 0x000ba4, 0x000ba8, 0x000baa, 0x000bae, 0x000bb9, 0x000bbe, 0x000bc2, 0x000bc6, 0x000bc8, 0x000bca, 0x000bcc, 0x000bd0, 0x000bd0, 0x000bd7, 0x000bd7, + 0x000c00, 0x000c03, 0x000c05, 0x000c0c, 0x000c0e, 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3d, 0x000c44, 0x000c46, 0x000c48, 0x000c4a, 0x000c4c, 0x000c55, + 0x000c56, 0x000c58, 0x000c5a, 0x000c5d, 0x000c5d, 0x000c60, 0x000c63, 0x000c80, 0x000c83, 0x000c85, 0x000c8c, 0x000c8e, 0x000c90, 0x000c92, 0x000ca8, 0x000caa, 0x000cb3, + 0x000cb5, 0x000cb9, 0x000cbd, 0x000cc4, 0x000cc6, 0x000cc8, 0x000cca, 0x000ccc, 0x000cd5, 0x000cd6, 0x000cdd, 0x000cde, 0x000ce0, 0x000ce3, 0x000cf1, 0x000cf2, 0x000d00, + 0x000d0c, 0x000d0e, 0x000d10, 0x000d12, 0x000d3a, 0x000d3d, 0x000d44, 0x000d46, 0x000d48, 0x000d4a, 0x000d4c, 0x000d4e, 0x000d4e, 0x000d54, 0x000d57, 0x000d5f, 0x000d63, + 0x000d7a, 0x000d7f, 0x000d81, 0x000d83, 0x000d85, 0x000d96, 0x000d9a, 0x000db1, 0x000db3, 0x000dbb, 0x000dbd, 0x000dbd, 0x000dc0, 0x000dc6, 0x000dcf, 0x000dd4, 0x000dd6, + 0x000dd6, 0x000dd8, 0x000ddf, 0x000df2, 0x000df3, 0x000e01, 0x000e3a, 0x000e40, 0x000e46, 0x000e4d, 0x000e4d, 0x000e81, 0x000e82, 0x000e84, 0x000e84, 0x000e86, 0x000e8a, + 0x000e8c, 0x000ea3, 0x000ea5, 0x000ea5, 0x000ea7, 0x000eb9, 0x000ebb, 0x000ebd, 0x000ec0, 0x000ec4, 0x000ec6, 0x000ec6, 0x000ecd, 0x000ecd, 0x000edc, 0x000edf, 0x000f00, + 0x000f00, 0x000f40, 0x000f47, 0x000f49, 0x000f6c, 0x000f71, 0x000f81, 0x000f88, 0x000f97, 0x000f99, 0x000fbc, 0x001000, 0x001036, 0x001038, 0x001038, 0x00103b, 0x00103f, + 0x001050, 0x00108f, 0x00109a, 0x00109d, 0x0010a0, 0x0010c5, 0x0010c7, 0x0010c7, 0x0010cd, 0x0010cd, 0x0010d0, 0x0010fa, 0x0010fc, 0x001248, 0x00124a, 0x00124d, 0x001250, + 0x001256, 0x001258, 0x001258, 0x00125a, 0x00125d, 0x001260, 0x001288, 0x00128a, 0x00128d, 0x001290, 0x0012b0, 0x0012b2, 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, + 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, 0x0012d8, 0x001310, 0x001312, 0x001315, 0x001318, 0x00135a, 0x001380, 0x00138f, 0x0013a0, 0x0013f5, 0x0013f8, 0x0013fd, 0x001401, + 0x00166c, 0x00166f, 0x00167f, 0x001681, 0x00169a, 0x0016a0, 0x0016ea, 0x0016ee, 0x0016f8, 0x001700, 0x001713, 0x00171f, 0x001733, 0x001740, 0x001753, 0x001760, 0x00176c, + 0x00176e, 0x001770, 0x001772, 0x001773, 0x001780, 0x0017b3, 0x0017b6, 0x0017c8, 0x0017d7, 0x0017d7, 0x0017dc, 0x0017dc, 0x001820, 0x001878, 0x001880, 0x0018aa, 0x0018b0, + 0x0018f5, 0x001900, 0x00191e, 0x001920, 0x00192b, 0x001930, 0x001938, 0x001950, 0x00196d, 0x001970, 0x001974, 0x001980, 0x0019ab, 0x0019b0, 0x0019c9, 0x001a00, 0x001a1b, + 0x001a20, 0x001a5e, 0x001a61, 0x001a74, 0x001aa7, 0x001aa7, 0x001abf, 0x001ac0, 0x001acc, 0x001ace, 0x001b00, 0x001b33, 0x001b35, 0x001b43, 0x001b45, 0x001b4c, 0x001b80, + 0x001ba9, 0x001bac, 0x001baf, 0x001bba, 0x001be5, 0x001be7, 0x001bf1, 0x001c00, 0x001c36, 0x001c4d, 0x001c4f, 0x001c5a, 0x001c7d, 0x001c80, 0x001c88, 0x001c90, 0x001cba, + 0x001cbd, 0x001cbf, 0x001ce9, 0x001cec, 0x001cee, 0x001cf3, 0x001cf5, 0x001cf6, 0x001cfa, 0x001cfa, 0x001d00, 0x001dbf, 0x001de7, 0x001df4, 0x001e00, 0x001f15, 0x001f18, + 0x001f1d, 0x001f20, 0x001f45, 0x001f48, 0x001f4d, 0x001f50, 0x001f57, 0x001f59, 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f7d, 0x001f80, 0x001fb4, + 0x001fb6, 0x001fbc, 0x001fbe, 0x001fbe, 0x001fc2, 0x001fc4, 0x001fc6, 0x001fcc, 0x001fd0, 0x001fd3, 0x001fd6, 0x001fdb, 0x001fe0, 0x001fec, 0x001ff2, 0x001ff4, 0x001ff6, + 0x001ffc, 0x002071, 0x002071, 0x00207f, 0x00207f, 0x002090, 0x00209c, 0x002102, 0x002102, 0x002107, 0x002107, 0x00210a, 0x002113, 0x002115, 0x002115, 0x002119, 0x00211d, + 0x002124, 0x002124, 0x002126, 0x002126, 0x002128, 0x002128, 0x00212a, 0x00212d, 0x00212f, 0x002139, 0x00213c, 0x00213f, 0x002145, 0x002149, 0x00214e, 0x00214e, 0x002160, + 0x002188, 0x0024b6, 0x0024e9, 0x002c00, 0x002ce4, 0x002ceb, 0x002cee, 0x002cf2, 0x002cf3, 0x002d00, 0x002d25, 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, 0x002d30, 0x002d67, 0x002d6f, 0x002d6f, 0x002d80, 0x002d96, 0x002da0, 0x002da6, 0x002da8, 0x002dae, 0x002db0, 0x002db6, 0x002db8, 0x002dbe, 0x002dc0, 0x002dc6, 0x002dc8, 0x002dce, 0x002dd0, 0x002dd6, 0x002dd8, 0x002dde, 0x002de0, 0x002dff, 0x002e2f, 0x002e2f, 0x003005, 0x003007, 0x003021, 0x003029, 0x003031, 0x003035, 0x003038, 0x00303c, 0x003041, 0x003096, 0x00309d, 0x00309f, 0x0030a1, 0x0030fa, 0x0030fc, 0x0030ff, 0x003105, 0x00312f, 0x003131, 0x00318e, 0x0031a0, 0x0031bf, 0x0031f0, 0x0031ff, 0x003400, 0x004dbf, 0x004e00, - 0x009ffc, 0x00a000, 0x00a48c, 0x00a4d0, 0x00a4fd, 0x00a500, 0x00a60c, 0x00a610, 0x00a61f, 0x00a62a, 0x00a62b, 0x00a640, 0x00a66e, 0x00a674, 0x00a67b, 0x00a67f, 0x00a6ef, - 0x00a717, 0x00a71f, 0x00a722, 0x00a788, 0x00a78b, 0x00a7bf, 0x00a7c2, 0x00a7ca, 0x00a7f5, 0x00a805, 0x00a807, 0x00a827, 0x00a840, 0x00a873, 0x00a880, 0x00a8c3, 0x00a8c5, - 0x00a8c5, 0x00a8f2, 0x00a8f7, 0x00a8fb, 0x00a8fb, 0x00a8fd, 0x00a8ff, 0x00a90a, 0x00a92a, 0x00a930, 0x00a952, 0x00a960, 0x00a97c, 0x00a980, 0x00a9b2, 0x00a9b4, 0x00a9bf, - 0x00a9cf, 0x00a9cf, 0x00a9e0, 0x00a9ef, 0x00a9fa, 0x00a9fe, 0x00aa00, 0x00aa36, 0x00aa40, 0x00aa4d, 0x00aa60, 0x00aa76, 0x00aa7a, 0x00aabe, 0x00aac0, 0x00aac0, 0x00aac2, - 0x00aac2, 0x00aadb, 0x00aadd, 0x00aae0, 0x00aaef, 0x00aaf2, 0x00aaf5, 0x00ab01, 0x00ab06, 0x00ab09, 0x00ab0e, 0x00ab11, 0x00ab16, 0x00ab20, 0x00ab26, 0x00ab28, 0x00ab2e, - 0x00ab30, 0x00ab5a, 0x00ab5c, 0x00ab69, 0x00ab70, 0x00abea, 0x00ac00, 0x00d7a3, 0x00d7b0, 0x00d7c6, 0x00d7cb, 0x00d7fb, 0x00f900, 0x00fa6d, 0x00fa70, 0x00fad9, 0x00fb00, - 0x00fb06, 0x00fb13, 0x00fb17, 0x00fb1d, 0x00fb28, 0x00fb2a, 0x00fb36, 0x00fb38, 0x00fb3c, 0x00fb3e, 0x00fb3e, 0x00fb40, 0x00fb41, 0x00fb43, 0x00fb44, 0x00fb46, 0x00fbb1, - 0x00fbd3, 0x00fd3d, 0x00fd50, 0x00fd8f, 0x00fd92, 0x00fdc7, 0x00fdf0, 0x00fdfb, 0x00fe70, 0x00fe74, 0x00fe76, 0x00fefc, 0x00ff21, 0x00ff3a, 0x00ff41, 0x00ff5a, 0x00ff66, - 0x00ffbe, 0x00ffc2, 0x00ffc7, 0x00ffca, 0x00ffcf, 0x00ffd2, 0x00ffd7, 0x00ffda, 0x00ffdc, 0x010000, 0x01000b, 0x01000d, 0x010026, 0x010028, 0x01003a, 0x01003c, 0x01003d, - 0x01003f, 0x01004d, 0x010050, 0x01005d, 0x010080, 0x0100fa, 0x010140, 0x010174, 0x010280, 0x01029c, 0x0102a0, 0x0102d0, 0x010300, 0x01031f, 0x01032d, 0x01034a, 0x010350, - 0x01037a, 0x010380, 0x01039d, 0x0103a0, 0x0103c3, 0x0103c8, 0x0103cf, 0x0103d1, 0x0103d5, 0x010400, 0x01049d, 0x0104b0, 0x0104d3, 0x0104d8, 0x0104fb, 0x010500, 0x010527, - 0x010530, 0x010563, 0x010600, 0x010736, 0x010740, 0x010755, 0x010760, 0x010767, 0x010800, 0x010805, 0x010808, 0x010808, 0x01080a, 0x010835, 0x010837, 0x010838, 0x01083c, - 0x01083c, 0x01083f, 0x010855, 0x010860, 0x010876, 0x010880, 0x01089e, 0x0108e0, 0x0108f2, 0x0108f4, 0x0108f5, 0x010900, 0x010915, 0x010920, 0x010939, 0x010980, 0x0109b7, - 0x0109be, 0x0109bf, 0x010a00, 0x010a03, 0x010a05, 0x010a06, 0x010a0c, 0x010a13, 0x010a15, 0x010a17, 0x010a19, 0x010a35, 0x010a60, 0x010a7c, 0x010a80, 0x010a9c, 0x010ac0, - 0x010ac7, 0x010ac9, 0x010ae4, 0x010b00, 0x010b35, 0x010b40, 0x010b55, 0x010b60, 0x010b72, 0x010b80, 0x010b91, 0x010c00, 0x010c48, 0x010c80, 0x010cb2, 0x010cc0, 0x010cf2, - 0x010d00, 0x010d27, 0x010e80, 0x010ea9, 0x010eab, 0x010eac, 0x010eb0, 0x010eb1, 0x010f00, 0x010f1c, 0x010f27, 0x010f27, 0x010f30, 0x010f45, 0x010fb0, 0x010fc4, 0x010fe0, - 0x010ff6, 0x011000, 0x011045, 0x011082, 0x0110b8, 0x0110d0, 0x0110e8, 0x011100, 0x011132, 0x011144, 0x011147, 0x011150, 0x011172, 0x011176, 0x011176, 0x011180, 0x0111bf, - 0x0111c1, 0x0111c4, 0x0111ce, 0x0111cf, 0x0111da, 0x0111da, 0x0111dc, 0x0111dc, 0x011200, 0x011211, 0x011213, 0x011234, 0x011237, 0x011237, 0x01123e, 0x01123e, 0x011280, - 0x011286, 0x011288, 0x011288, 0x01128a, 0x01128d, 0x01128f, 0x01129d, 0x01129f, 0x0112a8, 0x0112b0, 0x0112e8, 0x011300, 0x011303, 0x011305, 0x01130c, 0x01130f, 0x011310, - 0x011313, 0x011328, 0x01132a, 0x011330, 0x011332, 0x011333, 0x011335, 0x011339, 0x01133d, 0x011344, 0x011347, 0x011348, 0x01134b, 0x01134c, 0x011350, 0x011350, 0x011357, - 0x011357, 0x01135d, 0x011363, 0x011400, 0x011441, 0x011443, 0x011445, 0x011447, 0x01144a, 0x01145f, 0x011461, 0x011480, 0x0114c1, 0x0114c4, 0x0114c5, 0x0114c7, 0x0114c7, - 0x011580, 0x0115b5, 0x0115b8, 0x0115be, 0x0115d8, 0x0115dd, 0x011600, 0x01163e, 0x011640, 0x011640, 0x011644, 0x011644, 0x011680, 0x0116b5, 0x0116b8, 0x0116b8, 0x011700, - 0x01171a, 0x01171d, 0x01172a, 0x011800, 0x011838, 0x0118a0, 0x0118df, 0x0118ff, 0x011906, 0x011909, 0x011909, 0x01190c, 0x011913, 0x011915, 0x011916, 0x011918, 0x011935, - 0x011937, 0x011938, 0x01193b, 0x01193c, 0x01193f, 0x011942, 0x0119a0, 0x0119a7, 0x0119aa, 0x0119d7, 0x0119da, 0x0119df, 0x0119e1, 0x0119e1, 0x0119e3, 0x0119e4, 0x011a00, - 0x011a32, 0x011a35, 0x011a3e, 0x011a50, 0x011a97, 0x011a9d, 0x011a9d, 0x011ac0, 0x011af8, 0x011c00, 0x011c08, 0x011c0a, 0x011c36, 0x011c38, 0x011c3e, 0x011c40, 0x011c40, - 0x011c72, 0x011c8f, 0x011c92, 0x011ca7, 0x011ca9, 0x011cb6, 0x011d00, 0x011d06, 0x011d08, 0x011d09, 0x011d0b, 0x011d36, 0x011d3a, 0x011d3a, 0x011d3c, 0x011d3d, 0x011d3f, - 0x011d41, 0x011d43, 0x011d43, 0x011d46, 0x011d47, 0x011d60, 0x011d65, 0x011d67, 0x011d68, 0x011d6a, 0x011d8e, 0x011d90, 0x011d91, 0x011d93, 0x011d96, 0x011d98, 0x011d98, - 0x011ee0, 0x011ef6, 0x011fb0, 0x011fb0, 0x012000, 0x012399, 0x012400, 0x01246e, 0x012480, 0x012543, 0x013000, 0x01342e, 0x014400, 0x014646, 0x016800, 0x016a38, 0x016a40, - 0x016a5e, 0x016ad0, 0x016aed, 0x016b00, 0x016b2f, 0x016b40, 0x016b43, 0x016b63, 0x016b77, 0x016b7d, 0x016b8f, 0x016e40, 0x016e7f, 0x016f00, 0x016f4a, 0x016f4f, 0x016f87, - 0x016f8f, 0x016f9f, 0x016fe0, 0x016fe1, 0x016fe3, 0x016fe3, 0x016ff0, 0x016ff1, 0x017000, 0x0187f7, 0x018800, 0x018cd5, 0x018d00, 0x018d08, 0x01b000, 0x01b11e, 0x01b150, - 0x01b152, 0x01b164, 0x01b167, 0x01b170, 0x01b2fb, 0x01bc00, 0x01bc6a, 0x01bc70, 0x01bc7c, 0x01bc80, 0x01bc88, 0x01bc90, 0x01bc99, 0x01bc9e, 0x01bc9e, 0x01d400, 0x01d454, - 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, - 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, - 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d6c0, 0x01d6c2, 0x01d6da, 0x01d6dc, 0x01d6fa, 0x01d6fc, 0x01d714, 0x01d716, 0x01d734, 0x01d736, 0x01d74e, 0x01d750, 0x01d76e, 0x01d770, - 0x01d788, 0x01d78a, 0x01d7a8, 0x01d7aa, 0x01d7c2, 0x01d7c4, 0x01d7cb, 0x01e000, 0x01e006, 0x01e008, 0x01e018, 0x01e01b, 0x01e021, 0x01e023, 0x01e024, 0x01e026, 0x01e02a, - 0x01e100, 0x01e12c, 0x01e137, 0x01e13d, 0x01e14e, 0x01e14e, 0x01e2c0, 0x01e2eb, 0x01e800, 0x01e8c4, 0x01e900, 0x01e943, 0x01e947, 0x01e947, 0x01e94b, 0x01e94b, 0x01ee00, - 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, 0x01ee39, 0x01ee3b, 0x01ee3b, - 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, 0x01ee57, 0x01ee57, 0x01ee59, - 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, 0x01ee72, 0x01ee74, 0x01ee77, - 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, 0x01ee80, 0x01ee89, 0x01ee8b, 0x01ee9b, 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, 0x01f130, 0x01f149, 0x01f150, - 0x01f169, 0x01f170, 0x01f189, 0x020000, 0x02a6dd, 0x02a700, 0x02b734, 0x02b740, 0x02b81d, 0x02b820, 0x02cea1, 0x02ceb0, 0x02ebe0, 0x02f800, 0x02fa1d, 0x030000, 0x03134a)); + 0x00a48c, 0x00a4d0, 0x00a4fd, 0x00a500, 0x00a60c, 0x00a610, 0x00a61f, 0x00a62a, 0x00a62b, 0x00a640, 0x00a66e, 0x00a674, 0x00a67b, 0x00a67f, 0x00a6ef, 0x00a717, 0x00a71f, + 0x00a722, 0x00a788, 0x00a78b, 0x00a7ca, 0x00a7d0, 0x00a7d1, 0x00a7d3, 0x00a7d3, 0x00a7d5, 0x00a7d9, 0x00a7f2, 0x00a805, 0x00a807, 0x00a827, 0x00a840, 0x00a873, 0x00a880, + 0x00a8c3, 0x00a8c5, 0x00a8c5, 0x00a8f2, 0x00a8f7, 0x00a8fb, 0x00a8fb, 0x00a8fd, 0x00a8ff, 0x00a90a, 0x00a92a, 0x00a930, 0x00a952, 0x00a960, 0x00a97c, 0x00a980, 0x00a9b2, + 0x00a9b4, 0x00a9bf, 0x00a9cf, 0x00a9cf, 0x00a9e0, 0x00a9ef, 0x00a9fa, 0x00a9fe, 0x00aa00, 0x00aa36, 0x00aa40, 0x00aa4d, 0x00aa60, 0x00aa76, 0x00aa7a, 0x00aabe, 0x00aac0, + 0x00aac0, 0x00aac2, 0x00aac2, 0x00aadb, 0x00aadd, 0x00aae0, 0x00aaef, 0x00aaf2, 0x00aaf5, 0x00ab01, 0x00ab06, 0x00ab09, 0x00ab0e, 0x00ab11, 0x00ab16, 0x00ab20, 0x00ab26, + 0x00ab28, 0x00ab2e, 0x00ab30, 0x00ab5a, 0x00ab5c, 0x00ab69, 0x00ab70, 0x00abea, 0x00ac00, 0x00d7a3, 0x00d7b0, 0x00d7c6, 0x00d7cb, 0x00d7fb, 0x00f900, 0x00fa6d, 0x00fa70, + 0x00fad9, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, 0x00fb1d, 0x00fb28, 0x00fb2a, 0x00fb36, 0x00fb38, 0x00fb3c, 0x00fb3e, 0x00fb3e, 0x00fb40, 0x00fb41, 0x00fb43, 0x00fb44, + 0x00fb46, 0x00fbb1, 0x00fbd3, 0x00fd3d, 0x00fd50, 0x00fd8f, 0x00fd92, 0x00fdc7, 0x00fdf0, 0x00fdfb, 0x00fe70, 0x00fe74, 0x00fe76, 0x00fefc, 0x00ff21, 0x00ff3a, 0x00ff41, + 0x00ff5a, 0x00ff66, 0x00ffbe, 0x00ffc2, 0x00ffc7, 0x00ffca, 0x00ffcf, 0x00ffd2, 0x00ffd7, 0x00ffda, 0x00ffdc, 0x010000, 0x01000b, 0x01000d, 0x010026, 0x010028, 0x01003a, + 0x01003c, 0x01003d, 0x01003f, 0x01004d, 0x010050, 0x01005d, 0x010080, 0x0100fa, 0x010140, 0x010174, 0x010280, 0x01029c, 0x0102a0, 0x0102d0, 0x010300, 0x01031f, 0x01032d, + 0x01034a, 0x010350, 0x01037a, 0x010380, 0x01039d, 0x0103a0, 0x0103c3, 0x0103c8, 0x0103cf, 0x0103d1, 0x0103d5, 0x010400, 0x01049d, 0x0104b0, 0x0104d3, 0x0104d8, 0x0104fb, + 0x010500, 0x010527, 0x010530, 0x010563, 0x010570, 0x01057a, 0x01057c, 0x01058a, 0x01058c, 0x010592, 0x010594, 0x010595, 0x010597, 0x0105a1, 0x0105a3, 0x0105b1, 0x0105b3, + 0x0105b9, 0x0105bb, 0x0105bc, 0x010600, 0x010736, 0x010740, 0x010755, 0x010760, 0x010767, 0x010780, 0x010785, 0x010787, 0x0107b0, 0x0107b2, 0x0107ba, 0x010800, 0x010805, + 0x010808, 0x010808, 0x01080a, 0x010835, 0x010837, 0x010838, 0x01083c, 0x01083c, 0x01083f, 0x010855, 0x010860, 0x010876, 0x010880, 0x01089e, 0x0108e0, 0x0108f2, 0x0108f4, + 0x0108f5, 0x010900, 0x010915, 0x010920, 0x010939, 0x010980, 0x0109b7, 0x0109be, 0x0109bf, 0x010a00, 0x010a03, 0x010a05, 0x010a06, 0x010a0c, 0x010a13, 0x010a15, 0x010a17, + 0x010a19, 0x010a35, 0x010a60, 0x010a7c, 0x010a80, 0x010a9c, 0x010ac0, 0x010ac7, 0x010ac9, 0x010ae4, 0x010b00, 0x010b35, 0x010b40, 0x010b55, 0x010b60, 0x010b72, 0x010b80, + 0x010b91, 0x010c00, 0x010c48, 0x010c80, 0x010cb2, 0x010cc0, 0x010cf2, 0x010d00, 0x010d27, 0x010e80, 0x010ea9, 0x010eab, 0x010eac, 0x010eb0, 0x010eb1, 0x010f00, 0x010f1c, + 0x010f27, 0x010f27, 0x010f30, 0x010f45, 0x010f70, 0x010f81, 0x010fb0, 0x010fc4, 0x010fe0, 0x010ff6, 0x011000, 0x011045, 0x011071, 0x011075, 0x011082, 0x0110b8, 0x0110c2, + 0x0110c2, 0x0110d0, 0x0110e8, 0x011100, 0x011132, 0x011144, 0x011147, 0x011150, 0x011172, 0x011176, 0x011176, 0x011180, 0x0111bf, 0x0111c1, 0x0111c4, 0x0111ce, 0x0111cf, + 0x0111da, 0x0111da, 0x0111dc, 0x0111dc, 0x011200, 0x011211, 0x011213, 0x011234, 0x011237, 0x011237, 0x01123e, 0x01123e, 0x011280, 0x011286, 0x011288, 0x011288, 0x01128a, + 0x01128d, 0x01128f, 0x01129d, 0x01129f, 0x0112a8, 0x0112b0, 0x0112e8, 0x011300, 0x011303, 0x011305, 0x01130c, 0x01130f, 0x011310, 0x011313, 0x011328, 0x01132a, 0x011330, + 0x011332, 0x011333, 0x011335, 0x011339, 0x01133d, 0x011344, 0x011347, 0x011348, 0x01134b, 0x01134c, 0x011350, 0x011350, 0x011357, 0x011357, 0x01135d, 0x011363, 0x011400, + 0x011441, 0x011443, 0x011445, 0x011447, 0x01144a, 0x01145f, 0x011461, 0x011480, 0x0114c1, 0x0114c4, 0x0114c5, 0x0114c7, 0x0114c7, 0x011580, 0x0115b5, 0x0115b8, 0x0115be, + 0x0115d8, 0x0115dd, 0x011600, 0x01163e, 0x011640, 0x011640, 0x011644, 0x011644, 0x011680, 0x0116b5, 0x0116b8, 0x0116b8, 0x011700, 0x01171a, 0x01171d, 0x01172a, 0x011740, + 0x011746, 0x011800, 0x011838, 0x0118a0, 0x0118df, 0x0118ff, 0x011906, 0x011909, 0x011909, 0x01190c, 0x011913, 0x011915, 0x011916, 0x011918, 0x011935, 0x011937, 0x011938, + 0x01193b, 0x01193c, 0x01193f, 0x011942, 0x0119a0, 0x0119a7, 0x0119aa, 0x0119d7, 0x0119da, 0x0119df, 0x0119e1, 0x0119e1, 0x0119e3, 0x0119e4, 0x011a00, 0x011a32, 0x011a35, + 0x011a3e, 0x011a50, 0x011a97, 0x011a9d, 0x011a9d, 0x011ab0, 0x011af8, 0x011c00, 0x011c08, 0x011c0a, 0x011c36, 0x011c38, 0x011c3e, 0x011c40, 0x011c40, 0x011c72, 0x011c8f, + 0x011c92, 0x011ca7, 0x011ca9, 0x011cb6, 0x011d00, 0x011d06, 0x011d08, 0x011d09, 0x011d0b, 0x011d36, 0x011d3a, 0x011d3a, 0x011d3c, 0x011d3d, 0x011d3f, 0x011d41, 0x011d43, + 0x011d43, 0x011d46, 0x011d47, 0x011d60, 0x011d65, 0x011d67, 0x011d68, 0x011d6a, 0x011d8e, 0x011d90, 0x011d91, 0x011d93, 0x011d96, 0x011d98, 0x011d98, 0x011ee0, 0x011ef6, + 0x011fb0, 0x011fb0, 0x012000, 0x012399, 0x012400, 0x01246e, 0x012480, 0x012543, 0x012f90, 0x012ff0, 0x013000, 0x01342e, 0x014400, 0x014646, 0x016800, 0x016a38, 0x016a40, + 0x016a5e, 0x016a70, 0x016abe, 0x016ad0, 0x016aed, 0x016b00, 0x016b2f, 0x016b40, 0x016b43, 0x016b63, 0x016b77, 0x016b7d, 0x016b8f, 0x016e40, 0x016e7f, 0x016f00, 0x016f4a, + 0x016f4f, 0x016f87, 0x016f8f, 0x016f9f, 0x016fe0, 0x016fe1, 0x016fe3, 0x016fe3, 0x016ff0, 0x016ff1, 0x017000, 0x0187f7, 0x018800, 0x018cd5, 0x018d00, 0x018d08, 0x01aff0, + 0x01aff3, 0x01aff5, 0x01affb, 0x01affd, 0x01affe, 0x01b000, 0x01b122, 0x01b150, 0x01b152, 0x01b164, 0x01b167, 0x01b170, 0x01b2fb, 0x01bc00, 0x01bc6a, 0x01bc70, 0x01bc7c, + 0x01bc80, 0x01bc88, 0x01bc90, 0x01bc99, 0x01bc9e, 0x01bc9e, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, + 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, + 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d6c0, 0x01d6c2, 0x01d6da, 0x01d6dc, 0x01d6fa, 0x01d6fc, + 0x01d714, 0x01d716, 0x01d734, 0x01d736, 0x01d74e, 0x01d750, 0x01d76e, 0x01d770, 0x01d788, 0x01d78a, 0x01d7a8, 0x01d7aa, 0x01d7c2, 0x01d7c4, 0x01d7cb, 0x01df00, 0x01df1e, + 0x01e000, 0x01e006, 0x01e008, 0x01e018, 0x01e01b, 0x01e021, 0x01e023, 0x01e024, 0x01e026, 0x01e02a, 0x01e100, 0x01e12c, 0x01e137, 0x01e13d, 0x01e14e, 0x01e14e, 0x01e290, + 0x01e2ad, 0x01e2c0, 0x01e2eb, 0x01e7e0, 0x01e7e6, 0x01e7e8, 0x01e7eb, 0x01e7ed, 0x01e7ee, 0x01e7f0, 0x01e7fe, 0x01e800, 0x01e8c4, 0x01e900, 0x01e943, 0x01e947, 0x01e947, + 0x01e94b, 0x01e94b, 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, + 0x01ee39, 0x01ee3b, 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, + 0x01ee57, 0x01ee57, 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, + 0x01ee72, 0x01ee74, 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, 0x01ee80, 0x01ee89, 0x01ee8b, 0x01ee9b, 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, + 0x01f130, 0x01f149, 0x01f150, 0x01f169, 0x01f170, 0x01f189, 0x020000, 0x02a6df, 0x02a700, 0x02b738, 0x02b740, 0x02b81d, 0x02b820, 0x02cea1, 0x02ceb0, 0x02ebe0, 0x02f800, + 0x02fa1d, 0x030000, 0x03134a)); } private static void populateANY() { @@ -1063,20 +1083,20 @@ private static void populateANY() { private static void populateASSIGNED() { SET_ENCODINGS.put("Assigned", CodePointSet.createNoDedup(0x000000, 0x000377, 0x00037a, 0x00037f, 0x000384, 0x00038a, 0x00038c, 0x00038c, 0x00038e, 0x0003a1, 0x0003a3, 0x00052f, 0x000531, - 0x000556, 0x000559, 0x00058a, 0x00058d, 0x00058f, 0x000591, 0x0005c7, 0x0005d0, 0x0005ea, 0x0005ef, 0x0005f4, 0x000600, 0x00061c, 0x00061e, 0x00070d, 0x00070f, 0x00074a, - 0x00074d, 0x0007b1, 0x0007c0, 0x0007fa, 0x0007fd, 0x00082d, 0x000830, 0x00083e, 0x000840, 0x00085b, 0x00085e, 0x00085e, 0x000860, 0x00086a, 0x0008a0, 0x0008b4, 0x0008b6, - 0x0008c7, 0x0008d3, 0x000983, 0x000985, 0x00098c, 0x00098f, 0x000990, 0x000993, 0x0009a8, 0x0009aa, 0x0009b0, 0x0009b2, 0x0009b2, 0x0009b6, 0x0009b9, 0x0009bc, 0x0009c4, - 0x0009c7, 0x0009c8, 0x0009cb, 0x0009ce, 0x0009d7, 0x0009d7, 0x0009dc, 0x0009dd, 0x0009df, 0x0009e3, 0x0009e6, 0x0009fe, 0x000a01, 0x000a03, 0x000a05, 0x000a0a, 0x000a0f, - 0x000a10, 0x000a13, 0x000a28, 0x000a2a, 0x000a30, 0x000a32, 0x000a33, 0x000a35, 0x000a36, 0x000a38, 0x000a39, 0x000a3c, 0x000a3c, 0x000a3e, 0x000a42, 0x000a47, 0x000a48, - 0x000a4b, 0x000a4d, 0x000a51, 0x000a51, 0x000a59, 0x000a5c, 0x000a5e, 0x000a5e, 0x000a66, 0x000a76, 0x000a81, 0x000a83, 0x000a85, 0x000a8d, 0x000a8f, 0x000a91, 0x000a93, - 0x000aa8, 0x000aaa, 0x000ab0, 0x000ab2, 0x000ab3, 0x000ab5, 0x000ab9, 0x000abc, 0x000ac5, 0x000ac7, 0x000ac9, 0x000acb, 0x000acd, 0x000ad0, 0x000ad0, 0x000ae0, 0x000ae3, - 0x000ae6, 0x000af1, 0x000af9, 0x000aff, 0x000b01, 0x000b03, 0x000b05, 0x000b0c, 0x000b0f, 0x000b10, 0x000b13, 0x000b28, 0x000b2a, 0x000b30, 0x000b32, 0x000b33, 0x000b35, - 0x000b39, 0x000b3c, 0x000b44, 0x000b47, 0x000b48, 0x000b4b, 0x000b4d, 0x000b55, 0x000b57, 0x000b5c, 0x000b5d, 0x000b5f, 0x000b63, 0x000b66, 0x000b77, 0x000b82, 0x000b83, - 0x000b85, 0x000b8a, 0x000b8e, 0x000b90, 0x000b92, 0x000b95, 0x000b99, 0x000b9a, 0x000b9c, 0x000b9c, 0x000b9e, 0x000b9f, 0x000ba3, 0x000ba4, 0x000ba8, 0x000baa, 0x000bae, - 0x000bb9, 0x000bbe, 0x000bc2, 0x000bc6, 0x000bc8, 0x000bca, 0x000bcd, 0x000bd0, 0x000bd0, 0x000bd7, 0x000bd7, 0x000be6, 0x000bfa, 0x000c00, 0x000c0c, 0x000c0e, 0x000c10, - 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3d, 0x000c44, 0x000c46, 0x000c48, 0x000c4a, 0x000c4d, 0x000c55, 0x000c56, 0x000c58, 0x000c5a, 0x000c60, 0x000c63, 0x000c66, + 0x000556, 0x000559, 0x00058a, 0x00058d, 0x00058f, 0x000591, 0x0005c7, 0x0005d0, 0x0005ea, 0x0005ef, 0x0005f4, 0x000600, 0x00070d, 0x00070f, 0x00074a, 0x00074d, 0x0007b1, + 0x0007c0, 0x0007fa, 0x0007fd, 0x00082d, 0x000830, 0x00083e, 0x000840, 0x00085b, 0x00085e, 0x00085e, 0x000860, 0x00086a, 0x000870, 0x00088e, 0x000890, 0x000891, 0x000898, + 0x000983, 0x000985, 0x00098c, 0x00098f, 0x000990, 0x000993, 0x0009a8, 0x0009aa, 0x0009b0, 0x0009b2, 0x0009b2, 0x0009b6, 0x0009b9, 0x0009bc, 0x0009c4, 0x0009c7, 0x0009c8, + 0x0009cb, 0x0009ce, 0x0009d7, 0x0009d7, 0x0009dc, 0x0009dd, 0x0009df, 0x0009e3, 0x0009e6, 0x0009fe, 0x000a01, 0x000a03, 0x000a05, 0x000a0a, 0x000a0f, 0x000a10, 0x000a13, + 0x000a28, 0x000a2a, 0x000a30, 0x000a32, 0x000a33, 0x000a35, 0x000a36, 0x000a38, 0x000a39, 0x000a3c, 0x000a3c, 0x000a3e, 0x000a42, 0x000a47, 0x000a48, 0x000a4b, 0x000a4d, + 0x000a51, 0x000a51, 0x000a59, 0x000a5c, 0x000a5e, 0x000a5e, 0x000a66, 0x000a76, 0x000a81, 0x000a83, 0x000a85, 0x000a8d, 0x000a8f, 0x000a91, 0x000a93, 0x000aa8, 0x000aaa, + 0x000ab0, 0x000ab2, 0x000ab3, 0x000ab5, 0x000ab9, 0x000abc, 0x000ac5, 0x000ac7, 0x000ac9, 0x000acb, 0x000acd, 0x000ad0, 0x000ad0, 0x000ae0, 0x000ae3, 0x000ae6, 0x000af1, + 0x000af9, 0x000aff, 0x000b01, 0x000b03, 0x000b05, 0x000b0c, 0x000b0f, 0x000b10, 0x000b13, 0x000b28, 0x000b2a, 0x000b30, 0x000b32, 0x000b33, 0x000b35, 0x000b39, 0x000b3c, + 0x000b44, 0x000b47, 0x000b48, 0x000b4b, 0x000b4d, 0x000b55, 0x000b57, 0x000b5c, 0x000b5d, 0x000b5f, 0x000b63, 0x000b66, 0x000b77, 0x000b82, 0x000b83, 0x000b85, 0x000b8a, + 0x000b8e, 0x000b90, 0x000b92, 0x000b95, 0x000b99, 0x000b9a, 0x000b9c, 0x000b9c, 0x000b9e, 0x000b9f, 0x000ba3, 0x000ba4, 0x000ba8, 0x000baa, 0x000bae, 0x000bb9, 0x000bbe, + 0x000bc2, 0x000bc6, 0x000bc8, 0x000bca, 0x000bcd, 0x000bd0, 0x000bd0, 0x000bd7, 0x000bd7, 0x000be6, 0x000bfa, 0x000c00, 0x000c0c, 0x000c0e, 0x000c10, 0x000c12, 0x000c28, + 0x000c2a, 0x000c39, 0x000c3c, 0x000c44, 0x000c46, 0x000c48, 0x000c4a, 0x000c4d, 0x000c55, 0x000c56, 0x000c58, 0x000c5a, 0x000c5d, 0x000c5d, 0x000c60, 0x000c63, 0x000c66, 0x000c6f, 0x000c77, 0x000c8c, 0x000c8e, 0x000c90, 0x000c92, 0x000ca8, 0x000caa, 0x000cb3, 0x000cb5, 0x000cb9, 0x000cbc, 0x000cc4, 0x000cc6, 0x000cc8, 0x000cca, 0x000ccd, - 0x000cd5, 0x000cd6, 0x000cde, 0x000cde, 0x000ce0, 0x000ce3, 0x000ce6, 0x000cef, 0x000cf1, 0x000cf2, 0x000d00, 0x000d0c, 0x000d0e, 0x000d10, 0x000d12, 0x000d44, 0x000d46, + 0x000cd5, 0x000cd6, 0x000cdd, 0x000cde, 0x000ce0, 0x000ce3, 0x000ce6, 0x000cef, 0x000cf1, 0x000cf2, 0x000d00, 0x000d0c, 0x000d0e, 0x000d10, 0x000d12, 0x000d44, 0x000d46, 0x000d48, 0x000d4a, 0x000d4f, 0x000d54, 0x000d63, 0x000d66, 0x000d7f, 0x000d81, 0x000d83, 0x000d85, 0x000d96, 0x000d9a, 0x000db1, 0x000db3, 0x000dbb, 0x000dbd, 0x000dbd, 0x000dc0, 0x000dc6, 0x000dca, 0x000dca, 0x000dcf, 0x000dd4, 0x000dd6, 0x000dd6, 0x000dd8, 0x000ddf, 0x000de6, 0x000def, 0x000df2, 0x000df4, 0x000e01, 0x000e3a, 0x000e3f, 0x000e5b, 0x000e81, 0x000e82, 0x000e84, 0x000e84, 0x000e86, 0x000e8a, 0x000e8c, 0x000ea3, 0x000ea5, 0x000ea5, 0x000ea7, 0x000ebd, 0x000ec0, 0x000ec4, 0x000ec6, 0x000ec6, @@ -1084,64 +1104,67 @@ private static void populateASSIGNED() { 0x000fda, 0x001000, 0x0010c5, 0x0010c7, 0x0010c7, 0x0010cd, 0x0010cd, 0x0010d0, 0x001248, 0x00124a, 0x00124d, 0x001250, 0x001256, 0x001258, 0x001258, 0x00125a, 0x00125d, 0x001260, 0x001288, 0x00128a, 0x00128d, 0x001290, 0x0012b0, 0x0012b2, 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, 0x0012d8, 0x001310, 0x001312, 0x001315, 0x001318, 0x00135a, 0x00135d, 0x00137c, 0x001380, 0x001399, 0x0013a0, 0x0013f5, 0x0013f8, 0x0013fd, 0x001400, 0x00169c, 0x0016a0, 0x0016f8, - 0x001700, 0x00170c, 0x00170e, 0x001714, 0x001720, 0x001736, 0x001740, 0x001753, 0x001760, 0x00176c, 0x00176e, 0x001770, 0x001772, 0x001773, 0x001780, 0x0017dd, 0x0017e0, - 0x0017e9, 0x0017f0, 0x0017f9, 0x001800, 0x00180e, 0x001810, 0x001819, 0x001820, 0x001878, 0x001880, 0x0018aa, 0x0018b0, 0x0018f5, 0x001900, 0x00191e, 0x001920, 0x00192b, - 0x001930, 0x00193b, 0x001940, 0x001940, 0x001944, 0x00196d, 0x001970, 0x001974, 0x001980, 0x0019ab, 0x0019b0, 0x0019c9, 0x0019d0, 0x0019da, 0x0019de, 0x001a1b, 0x001a1e, - 0x001a5e, 0x001a60, 0x001a7c, 0x001a7f, 0x001a89, 0x001a90, 0x001a99, 0x001aa0, 0x001aad, 0x001ab0, 0x001ac0, 0x001b00, 0x001b4b, 0x001b50, 0x001b7c, 0x001b80, 0x001bf3, - 0x001bfc, 0x001c37, 0x001c3b, 0x001c49, 0x001c4d, 0x001c88, 0x001c90, 0x001cba, 0x001cbd, 0x001cc7, 0x001cd0, 0x001cfa, 0x001d00, 0x001df9, 0x001dfb, 0x001f15, 0x001f18, - 0x001f1d, 0x001f20, 0x001f45, 0x001f48, 0x001f4d, 0x001f50, 0x001f57, 0x001f59, 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f7d, 0x001f80, 0x001fb4, - 0x001fb6, 0x001fc4, 0x001fc6, 0x001fd3, 0x001fd6, 0x001fdb, 0x001fdd, 0x001fef, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ffe, 0x002000, 0x002064, 0x002066, 0x002071, 0x002074, - 0x00208e, 0x002090, 0x00209c, 0x0020a0, 0x0020bf, 0x0020d0, 0x0020f0, 0x002100, 0x00218b, 0x002190, 0x002426, 0x002440, 0x00244a, 0x002460, 0x002b73, 0x002b76, 0x002b95, - 0x002b97, 0x002c2e, 0x002c30, 0x002c5e, 0x002c60, 0x002cf3, 0x002cf9, 0x002d25, 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, 0x002d30, 0x002d67, 0x002d6f, 0x002d70, 0x002d7f, - 0x002d96, 0x002da0, 0x002da6, 0x002da8, 0x002dae, 0x002db0, 0x002db6, 0x002db8, 0x002dbe, 0x002dc0, 0x002dc6, 0x002dc8, 0x002dce, 0x002dd0, 0x002dd6, 0x002dd8, 0x002dde, - 0x002de0, 0x002e52, 0x002e80, 0x002e99, 0x002e9b, 0x002ef3, 0x002f00, 0x002fd5, 0x002ff0, 0x002ffb, 0x003000, 0x00303f, 0x003041, 0x003096, 0x003099, 0x0030ff, 0x003105, - 0x00312f, 0x003131, 0x00318e, 0x003190, 0x0031e3, 0x0031f0, 0x00321e, 0x003220, 0x009ffc, 0x00a000, 0x00a48c, 0x00a490, 0x00a4c6, 0x00a4d0, 0x00a62b, 0x00a640, 0x00a6f7, - 0x00a700, 0x00a7bf, 0x00a7c2, 0x00a7ca, 0x00a7f5, 0x00a82c, 0x00a830, 0x00a839, 0x00a840, 0x00a877, 0x00a880, 0x00a8c5, 0x00a8ce, 0x00a8d9, 0x00a8e0, 0x00a953, 0x00a95f, - 0x00a97c, 0x00a980, 0x00a9cd, 0x00a9cf, 0x00a9d9, 0x00a9de, 0x00a9fe, 0x00aa00, 0x00aa36, 0x00aa40, 0x00aa4d, 0x00aa50, 0x00aa59, 0x00aa5c, 0x00aac2, 0x00aadb, 0x00aaf6, - 0x00ab01, 0x00ab06, 0x00ab09, 0x00ab0e, 0x00ab11, 0x00ab16, 0x00ab20, 0x00ab26, 0x00ab28, 0x00ab2e, 0x00ab30, 0x00ab6b, 0x00ab70, 0x00abed, 0x00abf0, 0x00abf9, 0x00ac00, - 0x00d7a3, 0x00d7b0, 0x00d7c6, 0x00d7cb, 0x00d7fb, 0x00d800, 0x00fa6d, 0x00fa70, 0x00fad9, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, 0x00fb1d, 0x00fb36, 0x00fb38, 0x00fb3c, - 0x00fb3e, 0x00fb3e, 0x00fb40, 0x00fb41, 0x00fb43, 0x00fb44, 0x00fb46, 0x00fbc1, 0x00fbd3, 0x00fd3f, 0x00fd50, 0x00fd8f, 0x00fd92, 0x00fdc7, 0x00fdf0, 0x00fdfd, 0x00fe00, - 0x00fe19, 0x00fe20, 0x00fe52, 0x00fe54, 0x00fe66, 0x00fe68, 0x00fe6b, 0x00fe70, 0x00fe74, 0x00fe76, 0x00fefc, 0x00feff, 0x00feff, 0x00ff01, 0x00ffbe, 0x00ffc2, 0x00ffc7, - 0x00ffca, 0x00ffcf, 0x00ffd2, 0x00ffd7, 0x00ffda, 0x00ffdc, 0x00ffe0, 0x00ffe6, 0x00ffe8, 0x00ffee, 0x00fff9, 0x00fffd, 0x010000, 0x01000b, 0x01000d, 0x010026, 0x010028, - 0x01003a, 0x01003c, 0x01003d, 0x01003f, 0x01004d, 0x010050, 0x01005d, 0x010080, 0x0100fa, 0x010100, 0x010102, 0x010107, 0x010133, 0x010137, 0x01018e, 0x010190, 0x01019c, - 0x0101a0, 0x0101a0, 0x0101d0, 0x0101fd, 0x010280, 0x01029c, 0x0102a0, 0x0102d0, 0x0102e0, 0x0102fb, 0x010300, 0x010323, 0x01032d, 0x01034a, 0x010350, 0x01037a, 0x010380, - 0x01039d, 0x01039f, 0x0103c3, 0x0103c8, 0x0103d5, 0x010400, 0x01049d, 0x0104a0, 0x0104a9, 0x0104b0, 0x0104d3, 0x0104d8, 0x0104fb, 0x010500, 0x010527, 0x010530, 0x010563, - 0x01056f, 0x01056f, 0x010600, 0x010736, 0x010740, 0x010755, 0x010760, 0x010767, 0x010800, 0x010805, 0x010808, 0x010808, 0x01080a, 0x010835, 0x010837, 0x010838, 0x01083c, - 0x01083c, 0x01083f, 0x010855, 0x010857, 0x01089e, 0x0108a7, 0x0108af, 0x0108e0, 0x0108f2, 0x0108f4, 0x0108f5, 0x0108fb, 0x01091b, 0x01091f, 0x010939, 0x01093f, 0x01093f, - 0x010980, 0x0109b7, 0x0109bc, 0x0109cf, 0x0109d2, 0x010a03, 0x010a05, 0x010a06, 0x010a0c, 0x010a13, 0x010a15, 0x010a17, 0x010a19, 0x010a35, 0x010a38, 0x010a3a, 0x010a3f, - 0x010a48, 0x010a50, 0x010a58, 0x010a60, 0x010a9f, 0x010ac0, 0x010ae6, 0x010aeb, 0x010af6, 0x010b00, 0x010b35, 0x010b39, 0x010b55, 0x010b58, 0x010b72, 0x010b78, 0x010b91, - 0x010b99, 0x010b9c, 0x010ba9, 0x010baf, 0x010c00, 0x010c48, 0x010c80, 0x010cb2, 0x010cc0, 0x010cf2, 0x010cfa, 0x010d27, 0x010d30, 0x010d39, 0x010e60, 0x010e7e, 0x010e80, - 0x010ea9, 0x010eab, 0x010ead, 0x010eb0, 0x010eb1, 0x010f00, 0x010f27, 0x010f30, 0x010f59, 0x010fb0, 0x010fcb, 0x010fe0, 0x010ff6, 0x011000, 0x01104d, 0x011052, 0x01106f, - 0x01107f, 0x0110c1, 0x0110cd, 0x0110cd, 0x0110d0, 0x0110e8, 0x0110f0, 0x0110f9, 0x011100, 0x011134, 0x011136, 0x011147, 0x011150, 0x011176, 0x011180, 0x0111df, 0x0111e1, - 0x0111f4, 0x011200, 0x011211, 0x011213, 0x01123e, 0x011280, 0x011286, 0x011288, 0x011288, 0x01128a, 0x01128d, 0x01128f, 0x01129d, 0x01129f, 0x0112a9, 0x0112b0, 0x0112ea, - 0x0112f0, 0x0112f9, 0x011300, 0x011303, 0x011305, 0x01130c, 0x01130f, 0x011310, 0x011313, 0x011328, 0x01132a, 0x011330, 0x011332, 0x011333, 0x011335, 0x011339, 0x01133b, - 0x011344, 0x011347, 0x011348, 0x01134b, 0x01134d, 0x011350, 0x011350, 0x011357, 0x011357, 0x01135d, 0x011363, 0x011366, 0x01136c, 0x011370, 0x011374, 0x011400, 0x01145b, - 0x01145d, 0x011461, 0x011480, 0x0114c7, 0x0114d0, 0x0114d9, 0x011580, 0x0115b5, 0x0115b8, 0x0115dd, 0x011600, 0x011644, 0x011650, 0x011659, 0x011660, 0x01166c, 0x011680, - 0x0116b8, 0x0116c0, 0x0116c9, 0x011700, 0x01171a, 0x01171d, 0x01172b, 0x011730, 0x01173f, 0x011800, 0x01183b, 0x0118a0, 0x0118f2, 0x0118ff, 0x011906, 0x011909, 0x011909, - 0x01190c, 0x011913, 0x011915, 0x011916, 0x011918, 0x011935, 0x011937, 0x011938, 0x01193b, 0x011946, 0x011950, 0x011959, 0x0119a0, 0x0119a7, 0x0119aa, 0x0119d7, 0x0119da, - 0x0119e4, 0x011a00, 0x011a47, 0x011a50, 0x011aa2, 0x011ac0, 0x011af8, 0x011c00, 0x011c08, 0x011c0a, 0x011c36, 0x011c38, 0x011c45, 0x011c50, 0x011c6c, 0x011c70, 0x011c8f, - 0x011c92, 0x011ca7, 0x011ca9, 0x011cb6, 0x011d00, 0x011d06, 0x011d08, 0x011d09, 0x011d0b, 0x011d36, 0x011d3a, 0x011d3a, 0x011d3c, 0x011d3d, 0x011d3f, 0x011d47, 0x011d50, - 0x011d59, 0x011d60, 0x011d65, 0x011d67, 0x011d68, 0x011d6a, 0x011d8e, 0x011d90, 0x011d91, 0x011d93, 0x011d98, 0x011da0, 0x011da9, 0x011ee0, 0x011ef8, 0x011fb0, 0x011fb0, - 0x011fc0, 0x011ff1, 0x011fff, 0x012399, 0x012400, 0x01246e, 0x012470, 0x012474, 0x012480, 0x012543, 0x013000, 0x01342e, 0x013430, 0x013438, 0x014400, 0x014646, 0x016800, - 0x016a38, 0x016a40, 0x016a5e, 0x016a60, 0x016a69, 0x016a6e, 0x016a6f, 0x016ad0, 0x016aed, 0x016af0, 0x016af5, 0x016b00, 0x016b45, 0x016b50, 0x016b59, 0x016b5b, 0x016b61, - 0x016b63, 0x016b77, 0x016b7d, 0x016b8f, 0x016e40, 0x016e9a, 0x016f00, 0x016f4a, 0x016f4f, 0x016f87, 0x016f8f, 0x016f9f, 0x016fe0, 0x016fe4, 0x016ff0, 0x016ff1, 0x017000, - 0x0187f7, 0x018800, 0x018cd5, 0x018d00, 0x018d08, 0x01b000, 0x01b11e, 0x01b150, 0x01b152, 0x01b164, 0x01b167, 0x01b170, 0x01b2fb, 0x01bc00, 0x01bc6a, 0x01bc70, 0x01bc7c, - 0x01bc80, 0x01bc88, 0x01bc90, 0x01bc99, 0x01bc9c, 0x01bca3, 0x01d000, 0x01d0f5, 0x01d100, 0x01d126, 0x01d129, 0x01d1e8, 0x01d200, 0x01d245, 0x01d2e0, 0x01d2f3, 0x01d300, - 0x01d356, 0x01d360, 0x01d378, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b9, - 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, - 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d7cb, 0x01d7ce, 0x01da8b, 0x01da9b, 0x01da9f, 0x01daa1, 0x01daaf, 0x01e000, 0x01e006, - 0x01e008, 0x01e018, 0x01e01b, 0x01e021, 0x01e023, 0x01e024, 0x01e026, 0x01e02a, 0x01e100, 0x01e12c, 0x01e130, 0x01e13d, 0x01e140, 0x01e149, 0x01e14e, 0x01e14f, 0x01e2c0, - 0x01e2f9, 0x01e2ff, 0x01e2ff, 0x01e800, 0x01e8c4, 0x01e8c7, 0x01e8d6, 0x01e900, 0x01e94b, 0x01e950, 0x01e959, 0x01e95e, 0x01e95f, 0x01ec71, 0x01ecb4, 0x01ed01, 0x01ed3d, - 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, 0x01ee39, 0x01ee3b, - 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, 0x01ee57, 0x01ee57, - 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, 0x01ee72, 0x01ee74, - 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, 0x01ee80, 0x01ee89, 0x01ee8b, 0x01ee9b, 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, 0x01eef0, 0x01eef1, - 0x01f000, 0x01f02b, 0x01f030, 0x01f093, 0x01f0a0, 0x01f0ae, 0x01f0b1, 0x01f0bf, 0x01f0c1, 0x01f0cf, 0x01f0d1, 0x01f0f5, 0x01f100, 0x01f1ad, 0x01f1e6, 0x01f202, 0x01f210, - 0x01f23b, 0x01f240, 0x01f248, 0x01f250, 0x01f251, 0x01f260, 0x01f265, 0x01f300, 0x01f6d7, 0x01f6e0, 0x01f6ec, 0x01f6f0, 0x01f6fc, 0x01f700, 0x01f773, 0x01f780, 0x01f7d8, - 0x01f7e0, 0x01f7eb, 0x01f800, 0x01f80b, 0x01f810, 0x01f847, 0x01f850, 0x01f859, 0x01f860, 0x01f887, 0x01f890, 0x01f8ad, 0x01f8b0, 0x01f8b1, 0x01f900, 0x01f978, 0x01f97a, - 0x01f9cb, 0x01f9cd, 0x01fa53, 0x01fa60, 0x01fa6d, 0x01fa70, 0x01fa74, 0x01fa78, 0x01fa7a, 0x01fa80, 0x01fa86, 0x01fa90, 0x01faa8, 0x01fab0, 0x01fab6, 0x01fac0, 0x01fac2, - 0x01fad0, 0x01fad6, 0x01fb00, 0x01fb92, 0x01fb94, 0x01fbca, 0x01fbf0, 0x01fbf9, 0x020000, 0x02a6dd, 0x02a700, 0x02b734, 0x02b740, 0x02b81d, 0x02b820, 0x02cea1, 0x02ceb0, - 0x02ebe0, 0x02f800, 0x02fa1d, 0x030000, 0x03134a, 0x0e0001, 0x0e0001, 0x0e0020, 0x0e007f, 0x0e0100, 0x0e01ef, 0x0f0000, 0x0ffffd, 0x100000, 0x10fffd)); + 0x001700, 0x001715, 0x00171f, 0x001736, 0x001740, 0x001753, 0x001760, 0x00176c, 0x00176e, 0x001770, 0x001772, 0x001773, 0x001780, 0x0017dd, 0x0017e0, 0x0017e9, 0x0017f0, + 0x0017f9, 0x001800, 0x001819, 0x001820, 0x001878, 0x001880, 0x0018aa, 0x0018b0, 0x0018f5, 0x001900, 0x00191e, 0x001920, 0x00192b, 0x001930, 0x00193b, 0x001940, 0x001940, + 0x001944, 0x00196d, 0x001970, 0x001974, 0x001980, 0x0019ab, 0x0019b0, 0x0019c9, 0x0019d0, 0x0019da, 0x0019de, 0x001a1b, 0x001a1e, 0x001a5e, 0x001a60, 0x001a7c, 0x001a7f, + 0x001a89, 0x001a90, 0x001a99, 0x001aa0, 0x001aad, 0x001ab0, 0x001ace, 0x001b00, 0x001b4c, 0x001b50, 0x001b7e, 0x001b80, 0x001bf3, 0x001bfc, 0x001c37, 0x001c3b, 0x001c49, + 0x001c4d, 0x001c88, 0x001c90, 0x001cba, 0x001cbd, 0x001cc7, 0x001cd0, 0x001cfa, 0x001d00, 0x001f15, 0x001f18, 0x001f1d, 0x001f20, 0x001f45, 0x001f48, 0x001f4d, 0x001f50, + 0x001f57, 0x001f59, 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f7d, 0x001f80, 0x001fb4, 0x001fb6, 0x001fc4, 0x001fc6, 0x001fd3, 0x001fd6, 0x001fdb, + 0x001fdd, 0x001fef, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ffe, 0x002000, 0x002064, 0x002066, 0x002071, 0x002074, 0x00208e, 0x002090, 0x00209c, 0x0020a0, 0x0020c0, 0x0020d0, + 0x0020f0, 0x002100, 0x00218b, 0x002190, 0x002426, 0x002440, 0x00244a, 0x002460, 0x002b73, 0x002b76, 0x002b95, 0x002b97, 0x002cf3, 0x002cf9, 0x002d25, 0x002d27, 0x002d27, + 0x002d2d, 0x002d2d, 0x002d30, 0x002d67, 0x002d6f, 0x002d70, 0x002d7f, 0x002d96, 0x002da0, 0x002da6, 0x002da8, 0x002dae, 0x002db0, 0x002db6, 0x002db8, 0x002dbe, 0x002dc0, + 0x002dc6, 0x002dc8, 0x002dce, 0x002dd0, 0x002dd6, 0x002dd8, 0x002dde, 0x002de0, 0x002e5d, 0x002e80, 0x002e99, 0x002e9b, 0x002ef3, 0x002f00, 0x002fd5, 0x002ff0, 0x002ffb, + 0x003000, 0x00303f, 0x003041, 0x003096, 0x003099, 0x0030ff, 0x003105, 0x00312f, 0x003131, 0x00318e, 0x003190, 0x0031e3, 0x0031f0, 0x00321e, 0x003220, 0x00a48c, 0x00a490, + 0x00a4c6, 0x00a4d0, 0x00a62b, 0x00a640, 0x00a6f7, 0x00a700, 0x00a7ca, 0x00a7d0, 0x00a7d1, 0x00a7d3, 0x00a7d3, 0x00a7d5, 0x00a7d9, 0x00a7f2, 0x00a82c, 0x00a830, 0x00a839, + 0x00a840, 0x00a877, 0x00a880, 0x00a8c5, 0x00a8ce, 0x00a8d9, 0x00a8e0, 0x00a953, 0x00a95f, 0x00a97c, 0x00a980, 0x00a9cd, 0x00a9cf, 0x00a9d9, 0x00a9de, 0x00a9fe, 0x00aa00, + 0x00aa36, 0x00aa40, 0x00aa4d, 0x00aa50, 0x00aa59, 0x00aa5c, 0x00aac2, 0x00aadb, 0x00aaf6, 0x00ab01, 0x00ab06, 0x00ab09, 0x00ab0e, 0x00ab11, 0x00ab16, 0x00ab20, 0x00ab26, + 0x00ab28, 0x00ab2e, 0x00ab30, 0x00ab6b, 0x00ab70, 0x00abed, 0x00abf0, 0x00abf9, 0x00ac00, 0x00d7a3, 0x00d7b0, 0x00d7c6, 0x00d7cb, 0x00d7fb, 0x00d800, 0x00fa6d, 0x00fa70, + 0x00fad9, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, 0x00fb1d, 0x00fb36, 0x00fb38, 0x00fb3c, 0x00fb3e, 0x00fb3e, 0x00fb40, 0x00fb41, 0x00fb43, 0x00fb44, 0x00fb46, 0x00fbc2, + 0x00fbd3, 0x00fd8f, 0x00fd92, 0x00fdc7, 0x00fdcf, 0x00fdcf, 0x00fdf0, 0x00fe19, 0x00fe20, 0x00fe52, 0x00fe54, 0x00fe66, 0x00fe68, 0x00fe6b, 0x00fe70, 0x00fe74, 0x00fe76, + 0x00fefc, 0x00feff, 0x00feff, 0x00ff01, 0x00ffbe, 0x00ffc2, 0x00ffc7, 0x00ffca, 0x00ffcf, 0x00ffd2, 0x00ffd7, 0x00ffda, 0x00ffdc, 0x00ffe0, 0x00ffe6, 0x00ffe8, 0x00ffee, + 0x00fff9, 0x00fffd, 0x010000, 0x01000b, 0x01000d, 0x010026, 0x010028, 0x01003a, 0x01003c, 0x01003d, 0x01003f, 0x01004d, 0x010050, 0x01005d, 0x010080, 0x0100fa, 0x010100, + 0x010102, 0x010107, 0x010133, 0x010137, 0x01018e, 0x010190, 0x01019c, 0x0101a0, 0x0101a0, 0x0101d0, 0x0101fd, 0x010280, 0x01029c, 0x0102a0, 0x0102d0, 0x0102e0, 0x0102fb, + 0x010300, 0x010323, 0x01032d, 0x01034a, 0x010350, 0x01037a, 0x010380, 0x01039d, 0x01039f, 0x0103c3, 0x0103c8, 0x0103d5, 0x010400, 0x01049d, 0x0104a0, 0x0104a9, 0x0104b0, + 0x0104d3, 0x0104d8, 0x0104fb, 0x010500, 0x010527, 0x010530, 0x010563, 0x01056f, 0x01057a, 0x01057c, 0x01058a, 0x01058c, 0x010592, 0x010594, 0x010595, 0x010597, 0x0105a1, + 0x0105a3, 0x0105b1, 0x0105b3, 0x0105b9, 0x0105bb, 0x0105bc, 0x010600, 0x010736, 0x010740, 0x010755, 0x010760, 0x010767, 0x010780, 0x010785, 0x010787, 0x0107b0, 0x0107b2, + 0x0107ba, 0x010800, 0x010805, 0x010808, 0x010808, 0x01080a, 0x010835, 0x010837, 0x010838, 0x01083c, 0x01083c, 0x01083f, 0x010855, 0x010857, 0x01089e, 0x0108a7, 0x0108af, + 0x0108e0, 0x0108f2, 0x0108f4, 0x0108f5, 0x0108fb, 0x01091b, 0x01091f, 0x010939, 0x01093f, 0x01093f, 0x010980, 0x0109b7, 0x0109bc, 0x0109cf, 0x0109d2, 0x010a03, 0x010a05, + 0x010a06, 0x010a0c, 0x010a13, 0x010a15, 0x010a17, 0x010a19, 0x010a35, 0x010a38, 0x010a3a, 0x010a3f, 0x010a48, 0x010a50, 0x010a58, 0x010a60, 0x010a9f, 0x010ac0, 0x010ae6, + 0x010aeb, 0x010af6, 0x010b00, 0x010b35, 0x010b39, 0x010b55, 0x010b58, 0x010b72, 0x010b78, 0x010b91, 0x010b99, 0x010b9c, 0x010ba9, 0x010baf, 0x010c00, 0x010c48, 0x010c80, + 0x010cb2, 0x010cc0, 0x010cf2, 0x010cfa, 0x010d27, 0x010d30, 0x010d39, 0x010e60, 0x010e7e, 0x010e80, 0x010ea9, 0x010eab, 0x010ead, 0x010eb0, 0x010eb1, 0x010f00, 0x010f27, + 0x010f30, 0x010f59, 0x010f70, 0x010f89, 0x010fb0, 0x010fcb, 0x010fe0, 0x010ff6, 0x011000, 0x01104d, 0x011052, 0x011075, 0x01107f, 0x0110c2, 0x0110cd, 0x0110cd, 0x0110d0, + 0x0110e8, 0x0110f0, 0x0110f9, 0x011100, 0x011134, 0x011136, 0x011147, 0x011150, 0x011176, 0x011180, 0x0111df, 0x0111e1, 0x0111f4, 0x011200, 0x011211, 0x011213, 0x01123e, + 0x011280, 0x011286, 0x011288, 0x011288, 0x01128a, 0x01128d, 0x01128f, 0x01129d, 0x01129f, 0x0112a9, 0x0112b0, 0x0112ea, 0x0112f0, 0x0112f9, 0x011300, 0x011303, 0x011305, + 0x01130c, 0x01130f, 0x011310, 0x011313, 0x011328, 0x01132a, 0x011330, 0x011332, 0x011333, 0x011335, 0x011339, 0x01133b, 0x011344, 0x011347, 0x011348, 0x01134b, 0x01134d, + 0x011350, 0x011350, 0x011357, 0x011357, 0x01135d, 0x011363, 0x011366, 0x01136c, 0x011370, 0x011374, 0x011400, 0x01145b, 0x01145d, 0x011461, 0x011480, 0x0114c7, 0x0114d0, + 0x0114d9, 0x011580, 0x0115b5, 0x0115b8, 0x0115dd, 0x011600, 0x011644, 0x011650, 0x011659, 0x011660, 0x01166c, 0x011680, 0x0116b9, 0x0116c0, 0x0116c9, 0x011700, 0x01171a, + 0x01171d, 0x01172b, 0x011730, 0x011746, 0x011800, 0x01183b, 0x0118a0, 0x0118f2, 0x0118ff, 0x011906, 0x011909, 0x011909, 0x01190c, 0x011913, 0x011915, 0x011916, 0x011918, + 0x011935, 0x011937, 0x011938, 0x01193b, 0x011946, 0x011950, 0x011959, 0x0119a0, 0x0119a7, 0x0119aa, 0x0119d7, 0x0119da, 0x0119e4, 0x011a00, 0x011a47, 0x011a50, 0x011aa2, + 0x011ab0, 0x011af8, 0x011c00, 0x011c08, 0x011c0a, 0x011c36, 0x011c38, 0x011c45, 0x011c50, 0x011c6c, 0x011c70, 0x011c8f, 0x011c92, 0x011ca7, 0x011ca9, 0x011cb6, 0x011d00, + 0x011d06, 0x011d08, 0x011d09, 0x011d0b, 0x011d36, 0x011d3a, 0x011d3a, 0x011d3c, 0x011d3d, 0x011d3f, 0x011d47, 0x011d50, 0x011d59, 0x011d60, 0x011d65, 0x011d67, 0x011d68, + 0x011d6a, 0x011d8e, 0x011d90, 0x011d91, 0x011d93, 0x011d98, 0x011da0, 0x011da9, 0x011ee0, 0x011ef8, 0x011fb0, 0x011fb0, 0x011fc0, 0x011ff1, 0x011fff, 0x012399, 0x012400, + 0x01246e, 0x012470, 0x012474, 0x012480, 0x012543, 0x012f90, 0x012ff2, 0x013000, 0x01342e, 0x013430, 0x013438, 0x014400, 0x014646, 0x016800, 0x016a38, 0x016a40, 0x016a5e, + 0x016a60, 0x016a69, 0x016a6e, 0x016abe, 0x016ac0, 0x016ac9, 0x016ad0, 0x016aed, 0x016af0, 0x016af5, 0x016b00, 0x016b45, 0x016b50, 0x016b59, 0x016b5b, 0x016b61, 0x016b63, + 0x016b77, 0x016b7d, 0x016b8f, 0x016e40, 0x016e9a, 0x016f00, 0x016f4a, 0x016f4f, 0x016f87, 0x016f8f, 0x016f9f, 0x016fe0, 0x016fe4, 0x016ff0, 0x016ff1, 0x017000, 0x0187f7, + 0x018800, 0x018cd5, 0x018d00, 0x018d08, 0x01aff0, 0x01aff3, 0x01aff5, 0x01affb, 0x01affd, 0x01affe, 0x01b000, 0x01b122, 0x01b150, 0x01b152, 0x01b164, 0x01b167, 0x01b170, + 0x01b2fb, 0x01bc00, 0x01bc6a, 0x01bc70, 0x01bc7c, 0x01bc80, 0x01bc88, 0x01bc90, 0x01bc99, 0x01bc9c, 0x01bca3, 0x01cf00, 0x01cf2d, 0x01cf30, 0x01cf46, 0x01cf50, 0x01cfc3, + 0x01d000, 0x01d0f5, 0x01d100, 0x01d126, 0x01d129, 0x01d1ea, 0x01d200, 0x01d245, 0x01d2e0, 0x01d2f3, 0x01d300, 0x01d356, 0x01d360, 0x01d378, 0x01d400, 0x01d454, 0x01d456, + 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, + 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, + 0x01d6a5, 0x01d6a8, 0x01d7cb, 0x01d7ce, 0x01da8b, 0x01da9b, 0x01da9f, 0x01daa1, 0x01daaf, 0x01df00, 0x01df1e, 0x01e000, 0x01e006, 0x01e008, 0x01e018, 0x01e01b, 0x01e021, + 0x01e023, 0x01e024, 0x01e026, 0x01e02a, 0x01e100, 0x01e12c, 0x01e130, 0x01e13d, 0x01e140, 0x01e149, 0x01e14e, 0x01e14f, 0x01e290, 0x01e2ae, 0x01e2c0, 0x01e2f9, 0x01e2ff, + 0x01e2ff, 0x01e7e0, 0x01e7e6, 0x01e7e8, 0x01e7eb, 0x01e7ed, 0x01e7ee, 0x01e7f0, 0x01e7fe, 0x01e800, 0x01e8c4, 0x01e8c7, 0x01e8d6, 0x01e900, 0x01e94b, 0x01e950, 0x01e959, + 0x01e95e, 0x01e95f, 0x01ec71, 0x01ecb4, 0x01ed01, 0x01ed3d, 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, 0x01ee27, 0x01ee29, + 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, 0x01ee39, 0x01ee3b, 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, 0x01ee4d, 0x01ee4f, + 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, 0x01ee57, 0x01ee57, 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, 0x01ee62, 0x01ee64, + 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, 0x01ee72, 0x01ee74, 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, 0x01ee80, 0x01ee89, 0x01ee8b, 0x01ee9b, 0x01eea1, 0x01eea3, + 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, 0x01eef0, 0x01eef1, 0x01f000, 0x01f02b, 0x01f030, 0x01f093, 0x01f0a0, 0x01f0ae, 0x01f0b1, 0x01f0bf, 0x01f0c1, 0x01f0cf, 0x01f0d1, + 0x01f0f5, 0x01f100, 0x01f1ad, 0x01f1e6, 0x01f202, 0x01f210, 0x01f23b, 0x01f240, 0x01f248, 0x01f250, 0x01f251, 0x01f260, 0x01f265, 0x01f300, 0x01f6d7, 0x01f6dd, 0x01f6ec, + 0x01f6f0, 0x01f6fc, 0x01f700, 0x01f773, 0x01f780, 0x01f7d8, 0x01f7e0, 0x01f7eb, 0x01f7f0, 0x01f7f0, 0x01f800, 0x01f80b, 0x01f810, 0x01f847, 0x01f850, 0x01f859, 0x01f860, + 0x01f887, 0x01f890, 0x01f8ad, 0x01f8b0, 0x01f8b1, 0x01f900, 0x01fa53, 0x01fa60, 0x01fa6d, 0x01fa70, 0x01fa74, 0x01fa78, 0x01fa7c, 0x01fa80, 0x01fa86, 0x01fa90, 0x01faac, + 0x01fab0, 0x01faba, 0x01fac0, 0x01fac5, 0x01fad0, 0x01fad9, 0x01fae0, 0x01fae7, 0x01faf0, 0x01faf6, 0x01fb00, 0x01fb92, 0x01fb94, 0x01fbca, 0x01fbf0, 0x01fbf9, 0x020000, + 0x02a6df, 0x02a700, 0x02b738, 0x02b740, 0x02b81d, 0x02b820, 0x02cea1, 0x02ceb0, 0x02ebe0, 0x02f800, 0x02fa1d, 0x030000, 0x03134a, 0x0e0001, 0x0e0001, 0x0e0020, 0x0e007f, + 0x0e0100, 0x0e01ef, 0x0f0000, 0x0ffffd, 0x100000, 0x10fffd)); } private static void populateBIDI_C() { @@ -1160,9 +1183,9 @@ private static void populateBIDI_M() { 0x002a0a, 0x002a1c, 0x002a1e, 0x002a21, 0x002a24, 0x002a24, 0x002a26, 0x002a26, 0x002a29, 0x002a29, 0x002a2b, 0x002a2e, 0x002a34, 0x002a35, 0x002a3c, 0x002a3e, 0x002a57, 0x002a58, 0x002a64, 0x002a65, 0x002a6a, 0x002a6d, 0x002a6f, 0x002a70, 0x002a73, 0x002a74, 0x002a79, 0x002aa3, 0x002aa6, 0x002aad, 0x002aaf, 0x002ad6, 0x002adc, 0x002adc, 0x002ade, 0x002ade, 0x002ae2, 0x002ae6, 0x002aec, 0x002aee, 0x002af3, 0x002af3, 0x002af7, 0x002afb, 0x002afd, 0x002afd, 0x002bfe, 0x002bfe, 0x002e02, 0x002e05, 0x002e09, - 0x002e0a, 0x002e0c, 0x002e0d, 0x002e1c, 0x002e1d, 0x002e20, 0x002e29, 0x003008, 0x003011, 0x003014, 0x00301b, 0x00fe59, 0x00fe5e, 0x00fe64, 0x00fe65, 0x00ff08, 0x00ff09, - 0x00ff1c, 0x00ff1c, 0x00ff1e, 0x00ff1e, 0x00ff3b, 0x00ff3b, 0x00ff3d, 0x00ff3d, 0x00ff5b, 0x00ff5b, 0x00ff5d, 0x00ff5d, 0x00ff5f, 0x00ff60, 0x00ff62, 0x00ff63, 0x01d6db, - 0x01d6db, 0x01d715, 0x01d715, 0x01d74f, 0x01d74f, 0x01d789, 0x01d789, 0x01d7c3, 0x01d7c3)); + 0x002e0a, 0x002e0c, 0x002e0d, 0x002e1c, 0x002e1d, 0x002e20, 0x002e29, 0x002e55, 0x002e5c, 0x003008, 0x003011, 0x003014, 0x00301b, 0x00fe59, 0x00fe5e, 0x00fe64, 0x00fe65, + 0x00ff08, 0x00ff09, 0x00ff1c, 0x00ff1c, 0x00ff1e, 0x00ff1e, 0x00ff3b, 0x00ff3b, 0x00ff3d, 0x00ff3d, 0x00ff5b, 0x00ff5b, 0x00ff5d, 0x00ff5d, 0x00ff5f, 0x00ff60, 0x00ff62, + 0x00ff63, 0x01d6db, 0x01d6db, 0x01d715, 0x01d715, 0x01d74f, 0x01d74f, 0x01d789, 0x01d789, 0x01d7c3, 0x01d7c3)); } private static void populateCI() { @@ -1171,49 +1194,51 @@ private static void populateCI() { 0x000489, 0x000559, 0x000559, 0x00055f, 0x00055f, 0x000591, 0x0005bd, 0x0005bf, 0x0005bf, 0x0005c1, 0x0005c2, 0x0005c4, 0x0005c5, 0x0005c7, 0x0005c7, 0x0005f4, 0x0005f4, 0x000600, 0x000605, 0x000610, 0x00061a, 0x00061c, 0x00061c, 0x000640, 0x000640, 0x00064b, 0x00065f, 0x000670, 0x000670, 0x0006d6, 0x0006dd, 0x0006df, 0x0006e8, 0x0006ea, 0x0006ed, 0x00070f, 0x00070f, 0x000711, 0x000711, 0x000730, 0x00074a, 0x0007a6, 0x0007b0, 0x0007eb, 0x0007f5, 0x0007fa, 0x0007fa, 0x0007fd, 0x0007fd, 0x000816, 0x00082d, - 0x000859, 0x00085b, 0x0008d3, 0x000902, 0x00093a, 0x00093a, 0x00093c, 0x00093c, 0x000941, 0x000948, 0x00094d, 0x00094d, 0x000951, 0x000957, 0x000962, 0x000963, 0x000971, - 0x000971, 0x000981, 0x000981, 0x0009bc, 0x0009bc, 0x0009c1, 0x0009c4, 0x0009cd, 0x0009cd, 0x0009e2, 0x0009e3, 0x0009fe, 0x0009fe, 0x000a01, 0x000a02, 0x000a3c, 0x000a3c, - 0x000a41, 0x000a42, 0x000a47, 0x000a48, 0x000a4b, 0x000a4d, 0x000a51, 0x000a51, 0x000a70, 0x000a71, 0x000a75, 0x000a75, 0x000a81, 0x000a82, 0x000abc, 0x000abc, 0x000ac1, - 0x000ac5, 0x000ac7, 0x000ac8, 0x000acd, 0x000acd, 0x000ae2, 0x000ae3, 0x000afa, 0x000aff, 0x000b01, 0x000b01, 0x000b3c, 0x000b3c, 0x000b3f, 0x000b3f, 0x000b41, 0x000b44, - 0x000b4d, 0x000b4d, 0x000b55, 0x000b56, 0x000b62, 0x000b63, 0x000b82, 0x000b82, 0x000bc0, 0x000bc0, 0x000bcd, 0x000bcd, 0x000c00, 0x000c00, 0x000c04, 0x000c04, 0x000c3e, - 0x000c40, 0x000c46, 0x000c48, 0x000c4a, 0x000c4d, 0x000c55, 0x000c56, 0x000c62, 0x000c63, 0x000c81, 0x000c81, 0x000cbc, 0x000cbc, 0x000cbf, 0x000cbf, 0x000cc6, 0x000cc6, - 0x000ccc, 0x000ccd, 0x000ce2, 0x000ce3, 0x000d00, 0x000d01, 0x000d3b, 0x000d3c, 0x000d41, 0x000d44, 0x000d4d, 0x000d4d, 0x000d62, 0x000d63, 0x000d81, 0x000d81, 0x000dca, - 0x000dca, 0x000dd2, 0x000dd4, 0x000dd6, 0x000dd6, 0x000e31, 0x000e31, 0x000e34, 0x000e3a, 0x000e46, 0x000e4e, 0x000eb1, 0x000eb1, 0x000eb4, 0x000ebc, 0x000ec6, 0x000ec6, - 0x000ec8, 0x000ecd, 0x000f18, 0x000f19, 0x000f35, 0x000f35, 0x000f37, 0x000f37, 0x000f39, 0x000f39, 0x000f71, 0x000f7e, 0x000f80, 0x000f84, 0x000f86, 0x000f87, 0x000f8d, - 0x000f97, 0x000f99, 0x000fbc, 0x000fc6, 0x000fc6, 0x00102d, 0x001030, 0x001032, 0x001037, 0x001039, 0x00103a, 0x00103d, 0x00103e, 0x001058, 0x001059, 0x00105e, 0x001060, - 0x001071, 0x001074, 0x001082, 0x001082, 0x001085, 0x001086, 0x00108d, 0x00108d, 0x00109d, 0x00109d, 0x0010fc, 0x0010fc, 0x00135d, 0x00135f, 0x001712, 0x001714, 0x001732, - 0x001734, 0x001752, 0x001753, 0x001772, 0x001773, 0x0017b4, 0x0017b5, 0x0017b7, 0x0017bd, 0x0017c6, 0x0017c6, 0x0017c9, 0x0017d3, 0x0017d7, 0x0017d7, 0x0017dd, 0x0017dd, - 0x00180b, 0x00180e, 0x001843, 0x001843, 0x001885, 0x001886, 0x0018a9, 0x0018a9, 0x001920, 0x001922, 0x001927, 0x001928, 0x001932, 0x001932, 0x001939, 0x00193b, 0x001a17, - 0x001a18, 0x001a1b, 0x001a1b, 0x001a56, 0x001a56, 0x001a58, 0x001a5e, 0x001a60, 0x001a60, 0x001a62, 0x001a62, 0x001a65, 0x001a6c, 0x001a73, 0x001a7c, 0x001a7f, 0x001a7f, - 0x001aa7, 0x001aa7, 0x001ab0, 0x001ac0, 0x001b00, 0x001b03, 0x001b34, 0x001b34, 0x001b36, 0x001b3a, 0x001b3c, 0x001b3c, 0x001b42, 0x001b42, 0x001b6b, 0x001b73, 0x001b80, - 0x001b81, 0x001ba2, 0x001ba5, 0x001ba8, 0x001ba9, 0x001bab, 0x001bad, 0x001be6, 0x001be6, 0x001be8, 0x001be9, 0x001bed, 0x001bed, 0x001bef, 0x001bf1, 0x001c2c, 0x001c33, - 0x001c36, 0x001c37, 0x001c78, 0x001c7d, 0x001cd0, 0x001cd2, 0x001cd4, 0x001ce0, 0x001ce2, 0x001ce8, 0x001ced, 0x001ced, 0x001cf4, 0x001cf4, 0x001cf8, 0x001cf9, 0x001d2c, - 0x001d6a, 0x001d78, 0x001d78, 0x001d9b, 0x001df9, 0x001dfb, 0x001dff, 0x001fbd, 0x001fbd, 0x001fbf, 0x001fc1, 0x001fcd, 0x001fcf, 0x001fdd, 0x001fdf, 0x001fed, 0x001fef, - 0x001ffd, 0x001ffe, 0x00200b, 0x00200f, 0x002018, 0x002019, 0x002024, 0x002024, 0x002027, 0x002027, 0x00202a, 0x00202e, 0x002060, 0x002064, 0x002066, 0x00206f, 0x002071, - 0x002071, 0x00207f, 0x00207f, 0x002090, 0x00209c, 0x0020d0, 0x0020f0, 0x002c7c, 0x002c7d, 0x002cef, 0x002cf1, 0x002d6f, 0x002d6f, 0x002d7f, 0x002d7f, 0x002de0, 0x002dff, - 0x002e2f, 0x002e2f, 0x003005, 0x003005, 0x00302a, 0x00302d, 0x003031, 0x003035, 0x00303b, 0x00303b, 0x003099, 0x00309e, 0x0030fc, 0x0030fe, 0x00a015, 0x00a015, 0x00a4f8, - 0x00a4fd, 0x00a60c, 0x00a60c, 0x00a66f, 0x00a672, 0x00a674, 0x00a67d, 0x00a67f, 0x00a67f, 0x00a69c, 0x00a69f, 0x00a6f0, 0x00a6f1, 0x00a700, 0x00a721, 0x00a770, 0x00a770, - 0x00a788, 0x00a78a, 0x00a7f8, 0x00a7f9, 0x00a802, 0x00a802, 0x00a806, 0x00a806, 0x00a80b, 0x00a80b, 0x00a825, 0x00a826, 0x00a82c, 0x00a82c, 0x00a8c4, 0x00a8c5, 0x00a8e0, - 0x00a8f1, 0x00a8ff, 0x00a8ff, 0x00a926, 0x00a92d, 0x00a947, 0x00a951, 0x00a980, 0x00a982, 0x00a9b3, 0x00a9b3, 0x00a9b6, 0x00a9b9, 0x00a9bc, 0x00a9bd, 0x00a9cf, 0x00a9cf, - 0x00a9e5, 0x00a9e6, 0x00aa29, 0x00aa2e, 0x00aa31, 0x00aa32, 0x00aa35, 0x00aa36, 0x00aa43, 0x00aa43, 0x00aa4c, 0x00aa4c, 0x00aa70, 0x00aa70, 0x00aa7c, 0x00aa7c, 0x00aab0, - 0x00aab0, 0x00aab2, 0x00aab4, 0x00aab7, 0x00aab8, 0x00aabe, 0x00aabf, 0x00aac1, 0x00aac1, 0x00aadd, 0x00aadd, 0x00aaec, 0x00aaed, 0x00aaf3, 0x00aaf4, 0x00aaf6, 0x00aaf6, - 0x00ab5b, 0x00ab5f, 0x00ab69, 0x00ab6b, 0x00abe5, 0x00abe5, 0x00abe8, 0x00abe8, 0x00abed, 0x00abed, 0x00fb1e, 0x00fb1e, 0x00fbb2, 0x00fbc1, 0x00fe00, 0x00fe0f, 0x00fe13, - 0x00fe13, 0x00fe20, 0x00fe2f, 0x00fe52, 0x00fe52, 0x00fe55, 0x00fe55, 0x00feff, 0x00feff, 0x00ff07, 0x00ff07, 0x00ff0e, 0x00ff0e, 0x00ff1a, 0x00ff1a, 0x00ff3e, 0x00ff3e, - 0x00ff40, 0x00ff40, 0x00ff70, 0x00ff70, 0x00ff9e, 0x00ff9f, 0x00ffe3, 0x00ffe3, 0x00fff9, 0x00fffb, 0x0101fd, 0x0101fd, 0x0102e0, 0x0102e0, 0x010376, 0x01037a, 0x010a01, - 0x010a03, 0x010a05, 0x010a06, 0x010a0c, 0x010a0f, 0x010a38, 0x010a3a, 0x010a3f, 0x010a3f, 0x010ae5, 0x010ae6, 0x010d24, 0x010d27, 0x010eab, 0x010eac, 0x010f46, 0x010f50, - 0x011001, 0x011001, 0x011038, 0x011046, 0x01107f, 0x011081, 0x0110b3, 0x0110b6, 0x0110b9, 0x0110ba, 0x0110bd, 0x0110bd, 0x0110cd, 0x0110cd, 0x011100, 0x011102, 0x011127, - 0x01112b, 0x01112d, 0x011134, 0x011173, 0x011173, 0x011180, 0x011181, 0x0111b6, 0x0111be, 0x0111c9, 0x0111cc, 0x0111cf, 0x0111cf, 0x01122f, 0x011231, 0x011234, 0x011234, - 0x011236, 0x011237, 0x01123e, 0x01123e, 0x0112df, 0x0112df, 0x0112e3, 0x0112ea, 0x011300, 0x011301, 0x01133b, 0x01133c, 0x011340, 0x011340, 0x011366, 0x01136c, 0x011370, - 0x011374, 0x011438, 0x01143f, 0x011442, 0x011444, 0x011446, 0x011446, 0x01145e, 0x01145e, 0x0114b3, 0x0114b8, 0x0114ba, 0x0114ba, 0x0114bf, 0x0114c0, 0x0114c2, 0x0114c3, - 0x0115b2, 0x0115b5, 0x0115bc, 0x0115bd, 0x0115bf, 0x0115c0, 0x0115dc, 0x0115dd, 0x011633, 0x01163a, 0x01163d, 0x01163d, 0x01163f, 0x011640, 0x0116ab, 0x0116ab, 0x0116ad, - 0x0116ad, 0x0116b0, 0x0116b5, 0x0116b7, 0x0116b7, 0x01171d, 0x01171f, 0x011722, 0x011725, 0x011727, 0x01172b, 0x01182f, 0x011837, 0x011839, 0x01183a, 0x01193b, 0x01193c, - 0x01193e, 0x01193e, 0x011943, 0x011943, 0x0119d4, 0x0119d7, 0x0119da, 0x0119db, 0x0119e0, 0x0119e0, 0x011a01, 0x011a0a, 0x011a33, 0x011a38, 0x011a3b, 0x011a3e, 0x011a47, - 0x011a47, 0x011a51, 0x011a56, 0x011a59, 0x011a5b, 0x011a8a, 0x011a96, 0x011a98, 0x011a99, 0x011c30, 0x011c36, 0x011c38, 0x011c3d, 0x011c3f, 0x011c3f, 0x011c92, 0x011ca7, - 0x011caa, 0x011cb0, 0x011cb2, 0x011cb3, 0x011cb5, 0x011cb6, 0x011d31, 0x011d36, 0x011d3a, 0x011d3a, 0x011d3c, 0x011d3d, 0x011d3f, 0x011d45, 0x011d47, 0x011d47, 0x011d90, - 0x011d91, 0x011d95, 0x011d95, 0x011d97, 0x011d97, 0x011ef3, 0x011ef4, 0x013430, 0x013438, 0x016af0, 0x016af4, 0x016b30, 0x016b36, 0x016b40, 0x016b43, 0x016f4f, 0x016f4f, - 0x016f8f, 0x016f9f, 0x016fe0, 0x016fe1, 0x016fe3, 0x016fe4, 0x01bc9d, 0x01bc9e, 0x01bca0, 0x01bca3, 0x01d167, 0x01d169, 0x01d173, 0x01d182, 0x01d185, 0x01d18b, 0x01d1aa, - 0x01d1ad, 0x01d242, 0x01d244, 0x01da00, 0x01da36, 0x01da3b, 0x01da6c, 0x01da75, 0x01da75, 0x01da84, 0x01da84, 0x01da9b, 0x01da9f, 0x01daa1, 0x01daaf, 0x01e000, 0x01e006, - 0x01e008, 0x01e018, 0x01e01b, 0x01e021, 0x01e023, 0x01e024, 0x01e026, 0x01e02a, 0x01e130, 0x01e13d, 0x01e2ec, 0x01e2ef, 0x01e8d0, 0x01e8d6, 0x01e944, 0x01e94b, 0x01f3fb, + 0x000859, 0x00085b, 0x000888, 0x000888, 0x000890, 0x000891, 0x000898, 0x00089f, 0x0008c9, 0x000902, 0x00093a, 0x00093a, 0x00093c, 0x00093c, 0x000941, 0x000948, 0x00094d, + 0x00094d, 0x000951, 0x000957, 0x000962, 0x000963, 0x000971, 0x000971, 0x000981, 0x000981, 0x0009bc, 0x0009bc, 0x0009c1, 0x0009c4, 0x0009cd, 0x0009cd, 0x0009e2, 0x0009e3, + 0x0009fe, 0x0009fe, 0x000a01, 0x000a02, 0x000a3c, 0x000a3c, 0x000a41, 0x000a42, 0x000a47, 0x000a48, 0x000a4b, 0x000a4d, 0x000a51, 0x000a51, 0x000a70, 0x000a71, 0x000a75, + 0x000a75, 0x000a81, 0x000a82, 0x000abc, 0x000abc, 0x000ac1, 0x000ac5, 0x000ac7, 0x000ac8, 0x000acd, 0x000acd, 0x000ae2, 0x000ae3, 0x000afa, 0x000aff, 0x000b01, 0x000b01, + 0x000b3c, 0x000b3c, 0x000b3f, 0x000b3f, 0x000b41, 0x000b44, 0x000b4d, 0x000b4d, 0x000b55, 0x000b56, 0x000b62, 0x000b63, 0x000b82, 0x000b82, 0x000bc0, 0x000bc0, 0x000bcd, + 0x000bcd, 0x000c00, 0x000c00, 0x000c04, 0x000c04, 0x000c3c, 0x000c3c, 0x000c3e, 0x000c40, 0x000c46, 0x000c48, 0x000c4a, 0x000c4d, 0x000c55, 0x000c56, 0x000c62, 0x000c63, + 0x000c81, 0x000c81, 0x000cbc, 0x000cbc, 0x000cbf, 0x000cbf, 0x000cc6, 0x000cc6, 0x000ccc, 0x000ccd, 0x000ce2, 0x000ce3, 0x000d00, 0x000d01, 0x000d3b, 0x000d3c, 0x000d41, + 0x000d44, 0x000d4d, 0x000d4d, 0x000d62, 0x000d63, 0x000d81, 0x000d81, 0x000dca, 0x000dca, 0x000dd2, 0x000dd4, 0x000dd6, 0x000dd6, 0x000e31, 0x000e31, 0x000e34, 0x000e3a, + 0x000e46, 0x000e4e, 0x000eb1, 0x000eb1, 0x000eb4, 0x000ebc, 0x000ec6, 0x000ec6, 0x000ec8, 0x000ecd, 0x000f18, 0x000f19, 0x000f35, 0x000f35, 0x000f37, 0x000f37, 0x000f39, + 0x000f39, 0x000f71, 0x000f7e, 0x000f80, 0x000f84, 0x000f86, 0x000f87, 0x000f8d, 0x000f97, 0x000f99, 0x000fbc, 0x000fc6, 0x000fc6, 0x00102d, 0x001030, 0x001032, 0x001037, + 0x001039, 0x00103a, 0x00103d, 0x00103e, 0x001058, 0x001059, 0x00105e, 0x001060, 0x001071, 0x001074, 0x001082, 0x001082, 0x001085, 0x001086, 0x00108d, 0x00108d, 0x00109d, + 0x00109d, 0x0010fc, 0x0010fc, 0x00135d, 0x00135f, 0x001712, 0x001714, 0x001732, 0x001733, 0x001752, 0x001753, 0x001772, 0x001773, 0x0017b4, 0x0017b5, 0x0017b7, 0x0017bd, + 0x0017c6, 0x0017c6, 0x0017c9, 0x0017d3, 0x0017d7, 0x0017d7, 0x0017dd, 0x0017dd, 0x00180b, 0x00180f, 0x001843, 0x001843, 0x001885, 0x001886, 0x0018a9, 0x0018a9, 0x001920, + 0x001922, 0x001927, 0x001928, 0x001932, 0x001932, 0x001939, 0x00193b, 0x001a17, 0x001a18, 0x001a1b, 0x001a1b, 0x001a56, 0x001a56, 0x001a58, 0x001a5e, 0x001a60, 0x001a60, + 0x001a62, 0x001a62, 0x001a65, 0x001a6c, 0x001a73, 0x001a7c, 0x001a7f, 0x001a7f, 0x001aa7, 0x001aa7, 0x001ab0, 0x001ace, 0x001b00, 0x001b03, 0x001b34, 0x001b34, 0x001b36, + 0x001b3a, 0x001b3c, 0x001b3c, 0x001b42, 0x001b42, 0x001b6b, 0x001b73, 0x001b80, 0x001b81, 0x001ba2, 0x001ba5, 0x001ba8, 0x001ba9, 0x001bab, 0x001bad, 0x001be6, 0x001be6, + 0x001be8, 0x001be9, 0x001bed, 0x001bed, 0x001bef, 0x001bf1, 0x001c2c, 0x001c33, 0x001c36, 0x001c37, 0x001c78, 0x001c7d, 0x001cd0, 0x001cd2, 0x001cd4, 0x001ce0, 0x001ce2, + 0x001ce8, 0x001ced, 0x001ced, 0x001cf4, 0x001cf4, 0x001cf8, 0x001cf9, 0x001d2c, 0x001d6a, 0x001d78, 0x001d78, 0x001d9b, 0x001dff, 0x001fbd, 0x001fbd, 0x001fbf, 0x001fc1, + 0x001fcd, 0x001fcf, 0x001fdd, 0x001fdf, 0x001fed, 0x001fef, 0x001ffd, 0x001ffe, 0x00200b, 0x00200f, 0x002018, 0x002019, 0x002024, 0x002024, 0x002027, 0x002027, 0x00202a, + 0x00202e, 0x002060, 0x002064, 0x002066, 0x00206f, 0x002071, 0x002071, 0x00207f, 0x00207f, 0x002090, 0x00209c, 0x0020d0, 0x0020f0, 0x002c7c, 0x002c7d, 0x002cef, 0x002cf1, + 0x002d6f, 0x002d6f, 0x002d7f, 0x002d7f, 0x002de0, 0x002dff, 0x002e2f, 0x002e2f, 0x003005, 0x003005, 0x00302a, 0x00302d, 0x003031, 0x003035, 0x00303b, 0x00303b, 0x003099, + 0x00309e, 0x0030fc, 0x0030fe, 0x00a015, 0x00a015, 0x00a4f8, 0x00a4fd, 0x00a60c, 0x00a60c, 0x00a66f, 0x00a672, 0x00a674, 0x00a67d, 0x00a67f, 0x00a67f, 0x00a69c, 0x00a69f, + 0x00a6f0, 0x00a6f1, 0x00a700, 0x00a721, 0x00a770, 0x00a770, 0x00a788, 0x00a78a, 0x00a7f2, 0x00a7f4, 0x00a7f8, 0x00a7f9, 0x00a802, 0x00a802, 0x00a806, 0x00a806, 0x00a80b, + 0x00a80b, 0x00a825, 0x00a826, 0x00a82c, 0x00a82c, 0x00a8c4, 0x00a8c5, 0x00a8e0, 0x00a8f1, 0x00a8ff, 0x00a8ff, 0x00a926, 0x00a92d, 0x00a947, 0x00a951, 0x00a980, 0x00a982, + 0x00a9b3, 0x00a9b3, 0x00a9b6, 0x00a9b9, 0x00a9bc, 0x00a9bd, 0x00a9cf, 0x00a9cf, 0x00a9e5, 0x00a9e6, 0x00aa29, 0x00aa2e, 0x00aa31, 0x00aa32, 0x00aa35, 0x00aa36, 0x00aa43, + 0x00aa43, 0x00aa4c, 0x00aa4c, 0x00aa70, 0x00aa70, 0x00aa7c, 0x00aa7c, 0x00aab0, 0x00aab0, 0x00aab2, 0x00aab4, 0x00aab7, 0x00aab8, 0x00aabe, 0x00aabf, 0x00aac1, 0x00aac1, + 0x00aadd, 0x00aadd, 0x00aaec, 0x00aaed, 0x00aaf3, 0x00aaf4, 0x00aaf6, 0x00aaf6, 0x00ab5b, 0x00ab5f, 0x00ab69, 0x00ab6b, 0x00abe5, 0x00abe5, 0x00abe8, 0x00abe8, 0x00abed, + 0x00abed, 0x00fb1e, 0x00fb1e, 0x00fbb2, 0x00fbc2, 0x00fe00, 0x00fe0f, 0x00fe13, 0x00fe13, 0x00fe20, 0x00fe2f, 0x00fe52, 0x00fe52, 0x00fe55, 0x00fe55, 0x00feff, 0x00feff, + 0x00ff07, 0x00ff07, 0x00ff0e, 0x00ff0e, 0x00ff1a, 0x00ff1a, 0x00ff3e, 0x00ff3e, 0x00ff40, 0x00ff40, 0x00ff70, 0x00ff70, 0x00ff9e, 0x00ff9f, 0x00ffe3, 0x00ffe3, 0x00fff9, + 0x00fffb, 0x0101fd, 0x0101fd, 0x0102e0, 0x0102e0, 0x010376, 0x01037a, 0x010780, 0x010785, 0x010787, 0x0107b0, 0x0107b2, 0x0107ba, 0x010a01, 0x010a03, 0x010a05, 0x010a06, + 0x010a0c, 0x010a0f, 0x010a38, 0x010a3a, 0x010a3f, 0x010a3f, 0x010ae5, 0x010ae6, 0x010d24, 0x010d27, 0x010eab, 0x010eac, 0x010f46, 0x010f50, 0x010f82, 0x010f85, 0x011001, + 0x011001, 0x011038, 0x011046, 0x011070, 0x011070, 0x011073, 0x011074, 0x01107f, 0x011081, 0x0110b3, 0x0110b6, 0x0110b9, 0x0110ba, 0x0110bd, 0x0110bd, 0x0110c2, 0x0110c2, + 0x0110cd, 0x0110cd, 0x011100, 0x011102, 0x011127, 0x01112b, 0x01112d, 0x011134, 0x011173, 0x011173, 0x011180, 0x011181, 0x0111b6, 0x0111be, 0x0111c9, 0x0111cc, 0x0111cf, + 0x0111cf, 0x01122f, 0x011231, 0x011234, 0x011234, 0x011236, 0x011237, 0x01123e, 0x01123e, 0x0112df, 0x0112df, 0x0112e3, 0x0112ea, 0x011300, 0x011301, 0x01133b, 0x01133c, + 0x011340, 0x011340, 0x011366, 0x01136c, 0x011370, 0x011374, 0x011438, 0x01143f, 0x011442, 0x011444, 0x011446, 0x011446, 0x01145e, 0x01145e, 0x0114b3, 0x0114b8, 0x0114ba, + 0x0114ba, 0x0114bf, 0x0114c0, 0x0114c2, 0x0114c3, 0x0115b2, 0x0115b5, 0x0115bc, 0x0115bd, 0x0115bf, 0x0115c0, 0x0115dc, 0x0115dd, 0x011633, 0x01163a, 0x01163d, 0x01163d, + 0x01163f, 0x011640, 0x0116ab, 0x0116ab, 0x0116ad, 0x0116ad, 0x0116b0, 0x0116b5, 0x0116b7, 0x0116b7, 0x01171d, 0x01171f, 0x011722, 0x011725, 0x011727, 0x01172b, 0x01182f, + 0x011837, 0x011839, 0x01183a, 0x01193b, 0x01193c, 0x01193e, 0x01193e, 0x011943, 0x011943, 0x0119d4, 0x0119d7, 0x0119da, 0x0119db, 0x0119e0, 0x0119e0, 0x011a01, 0x011a0a, + 0x011a33, 0x011a38, 0x011a3b, 0x011a3e, 0x011a47, 0x011a47, 0x011a51, 0x011a56, 0x011a59, 0x011a5b, 0x011a8a, 0x011a96, 0x011a98, 0x011a99, 0x011c30, 0x011c36, 0x011c38, + 0x011c3d, 0x011c3f, 0x011c3f, 0x011c92, 0x011ca7, 0x011caa, 0x011cb0, 0x011cb2, 0x011cb3, 0x011cb5, 0x011cb6, 0x011d31, 0x011d36, 0x011d3a, 0x011d3a, 0x011d3c, 0x011d3d, + 0x011d3f, 0x011d45, 0x011d47, 0x011d47, 0x011d90, 0x011d91, 0x011d95, 0x011d95, 0x011d97, 0x011d97, 0x011ef3, 0x011ef4, 0x013430, 0x013438, 0x016af0, 0x016af4, 0x016b30, + 0x016b36, 0x016b40, 0x016b43, 0x016f4f, 0x016f4f, 0x016f8f, 0x016f9f, 0x016fe0, 0x016fe1, 0x016fe3, 0x016fe4, 0x01aff0, 0x01aff3, 0x01aff5, 0x01affb, 0x01affd, 0x01affe, + 0x01bc9d, 0x01bc9e, 0x01bca0, 0x01bca3, 0x01cf00, 0x01cf2d, 0x01cf30, 0x01cf46, 0x01d167, 0x01d169, 0x01d173, 0x01d182, 0x01d185, 0x01d18b, 0x01d1aa, 0x01d1ad, 0x01d242, + 0x01d244, 0x01da00, 0x01da36, 0x01da3b, 0x01da6c, 0x01da75, 0x01da75, 0x01da84, 0x01da84, 0x01da9b, 0x01da9f, 0x01daa1, 0x01daaf, 0x01e000, 0x01e006, 0x01e008, 0x01e018, + 0x01e01b, 0x01e021, 0x01e023, 0x01e024, 0x01e026, 0x01e02a, 0x01e130, 0x01e13d, 0x01e2ae, 0x01e2ae, 0x01e2ec, 0x01e2ef, 0x01e8d0, 0x01e8d6, 0x01e944, 0x01e94b, 0x01f3fb, 0x01f3ff, 0x0e0001, 0x0e0001, 0x0e0020, 0x0e007f, 0x0e0100, 0x0e01ef)); } @@ -1269,7 +1294,7 @@ private static void populateCWCF() { 0x001ef8, 0x001efa, 0x001efa, 0x001efc, 0x001efc, 0x001efe, 0x001efe, 0x001f08, 0x001f0f, 0x001f18, 0x001f1d, 0x001f28, 0x001f2f, 0x001f38, 0x001f3f, 0x001f48, 0x001f4d, 0x001f59, 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f5f, 0x001f68, 0x001f6f, 0x001f80, 0x001faf, 0x001fb2, 0x001fb4, 0x001fb7, 0x001fbc, 0x001fc2, 0x001fc4, 0x001fc7, 0x001fcc, 0x001fd8, 0x001fdb, 0x001fe8, 0x001fec, 0x001ff2, 0x001ff4, 0x001ff7, 0x001ffc, 0x002126, 0x002126, 0x00212a, 0x00212b, 0x002132, 0x002132, - 0x002160, 0x00216f, 0x002183, 0x002183, 0x0024b6, 0x0024cf, 0x002c00, 0x002c2e, 0x002c60, 0x002c60, 0x002c62, 0x002c64, 0x002c67, 0x002c67, 0x002c69, 0x002c69, 0x002c6b, + 0x002160, 0x00216f, 0x002183, 0x002183, 0x0024b6, 0x0024cf, 0x002c00, 0x002c2f, 0x002c60, 0x002c60, 0x002c62, 0x002c64, 0x002c67, 0x002c67, 0x002c69, 0x002c69, 0x002c6b, 0x002c6b, 0x002c6d, 0x002c70, 0x002c72, 0x002c72, 0x002c75, 0x002c75, 0x002c7e, 0x002c80, 0x002c82, 0x002c82, 0x002c84, 0x002c84, 0x002c86, 0x002c86, 0x002c88, 0x002c88, 0x002c8a, 0x002c8a, 0x002c8c, 0x002c8c, 0x002c8e, 0x002c8e, 0x002c90, 0x002c90, 0x002c92, 0x002c92, 0x002c94, 0x002c94, 0x002c96, 0x002c96, 0x002c98, 0x002c98, 0x002c9a, 0x002c9a, 0x002c9c, 0x002c9c, 0x002c9e, 0x002c9e, 0x002ca0, 0x002ca0, 0x002ca2, 0x002ca2, 0x002ca4, 0x002ca4, 0x002ca6, 0x002ca6, 0x002ca8, 0x002ca8, 0x002caa, 0x002caa, @@ -1288,9 +1313,10 @@ private static void populateCWCF() { 0x00a768, 0x00a768, 0x00a76a, 0x00a76a, 0x00a76c, 0x00a76c, 0x00a76e, 0x00a76e, 0x00a779, 0x00a779, 0x00a77b, 0x00a77b, 0x00a77d, 0x00a77e, 0x00a780, 0x00a780, 0x00a782, 0x00a782, 0x00a784, 0x00a784, 0x00a786, 0x00a786, 0x00a78b, 0x00a78b, 0x00a78d, 0x00a78d, 0x00a790, 0x00a790, 0x00a792, 0x00a792, 0x00a796, 0x00a796, 0x00a798, 0x00a798, 0x00a79a, 0x00a79a, 0x00a79c, 0x00a79c, 0x00a79e, 0x00a79e, 0x00a7a0, 0x00a7a0, 0x00a7a2, 0x00a7a2, 0x00a7a4, 0x00a7a4, 0x00a7a6, 0x00a7a6, 0x00a7a8, 0x00a7a8, 0x00a7aa, - 0x00a7ae, 0x00a7b0, 0x00a7b4, 0x00a7b6, 0x00a7b6, 0x00a7b8, 0x00a7b8, 0x00a7ba, 0x00a7ba, 0x00a7bc, 0x00a7bc, 0x00a7be, 0x00a7be, 0x00a7c2, 0x00a7c2, 0x00a7c4, 0x00a7c7, - 0x00a7c9, 0x00a7c9, 0x00a7f5, 0x00a7f5, 0x00ab70, 0x00abbf, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, 0x00ff21, 0x00ff3a, 0x010400, 0x010427, 0x0104b0, 0x0104d3, 0x010c80, - 0x010cb2, 0x0118a0, 0x0118bf, 0x016e40, 0x016e5f, 0x01e900, 0x01e921)); + 0x00a7ae, 0x00a7b0, 0x00a7b4, 0x00a7b6, 0x00a7b6, 0x00a7b8, 0x00a7b8, 0x00a7ba, 0x00a7ba, 0x00a7bc, 0x00a7bc, 0x00a7be, 0x00a7be, 0x00a7c0, 0x00a7c0, 0x00a7c2, 0x00a7c2, + 0x00a7c4, 0x00a7c7, 0x00a7c9, 0x00a7c9, 0x00a7d0, 0x00a7d0, 0x00a7d6, 0x00a7d6, 0x00a7d8, 0x00a7d8, 0x00a7f5, 0x00a7f5, 0x00ab70, 0x00abbf, 0x00fb00, 0x00fb06, 0x00fb13, + 0x00fb17, 0x00ff21, 0x00ff3a, 0x010400, 0x010427, 0x0104b0, 0x0104d3, 0x010570, 0x01057a, 0x01057c, 0x01058a, 0x01058c, 0x010592, 0x010594, 0x010595, 0x010c80, 0x010cb2, + 0x0118a0, 0x0118bf, 0x016e40, 0x016e5f, 0x01e900, 0x01e921)); } private static void populateCWCM() { @@ -1304,11 +1330,12 @@ private static void populateCWCM() { 0x001d7d, 0x001d7d, 0x001d8e, 0x001d8e, 0x001e00, 0x001e9b, 0x001e9e, 0x001e9e, 0x001ea0, 0x001f15, 0x001f18, 0x001f1d, 0x001f20, 0x001f45, 0x001f48, 0x001f4d, 0x001f50, 0x001f57, 0x001f59, 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f7d, 0x001f80, 0x001fb4, 0x001fb6, 0x001fbc, 0x001fbe, 0x001fbe, 0x001fc2, 0x001fc4, 0x001fc6, 0x001fcc, 0x001fd0, 0x001fd3, 0x001fd6, 0x001fdb, 0x001fe0, 0x001fec, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ffc, 0x002126, 0x002126, 0x00212a, 0x00212b, 0x002132, - 0x002132, 0x00214e, 0x00214e, 0x002160, 0x00217f, 0x002183, 0x002184, 0x0024b6, 0x0024e9, 0x002c00, 0x002c2e, 0x002c30, 0x002c5e, 0x002c60, 0x002c70, 0x002c72, 0x002c73, - 0x002c75, 0x002c76, 0x002c7e, 0x002ce3, 0x002ceb, 0x002cee, 0x002cf2, 0x002cf3, 0x002d00, 0x002d25, 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, 0x00a640, 0x00a66d, 0x00a680, - 0x00a69b, 0x00a722, 0x00a72f, 0x00a732, 0x00a76f, 0x00a779, 0x00a787, 0x00a78b, 0x00a78d, 0x00a790, 0x00a794, 0x00a796, 0x00a7ae, 0x00a7b0, 0x00a7bf, 0x00a7c2, 0x00a7ca, - 0x00a7f5, 0x00a7f6, 0x00ab53, 0x00ab53, 0x00ab70, 0x00abbf, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, 0x00ff21, 0x00ff3a, 0x00ff41, 0x00ff5a, 0x010400, 0x01044f, 0x0104b0, - 0x0104d3, 0x0104d8, 0x0104fb, 0x010c80, 0x010cb2, 0x010cc0, 0x010cf2, 0x0118a0, 0x0118df, 0x016e40, 0x016e7f, 0x01e900, 0x01e943)); + 0x002132, 0x00214e, 0x00214e, 0x002160, 0x00217f, 0x002183, 0x002184, 0x0024b6, 0x0024e9, 0x002c00, 0x002c70, 0x002c72, 0x002c73, 0x002c75, 0x002c76, 0x002c7e, 0x002ce3, + 0x002ceb, 0x002cee, 0x002cf2, 0x002cf3, 0x002d00, 0x002d25, 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, 0x00a640, 0x00a66d, 0x00a680, 0x00a69b, 0x00a722, 0x00a72f, 0x00a732, + 0x00a76f, 0x00a779, 0x00a787, 0x00a78b, 0x00a78d, 0x00a790, 0x00a794, 0x00a796, 0x00a7ae, 0x00a7b0, 0x00a7ca, 0x00a7d0, 0x00a7d1, 0x00a7d6, 0x00a7d9, 0x00a7f5, 0x00a7f6, + 0x00ab53, 0x00ab53, 0x00ab70, 0x00abbf, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, 0x00ff21, 0x00ff3a, 0x00ff41, 0x00ff5a, 0x010400, 0x01044f, 0x0104b0, 0x0104d3, 0x0104d8, + 0x0104fb, 0x010570, 0x01057a, 0x01057c, 0x01058a, 0x01058c, 0x010592, 0x010594, 0x010595, 0x010597, 0x0105a1, 0x0105a3, 0x0105b1, 0x0105b3, 0x0105b9, 0x0105bb, 0x0105bc, + 0x010c80, 0x010cb2, 0x010cc0, 0x010cf2, 0x0118a0, 0x0118df, 0x016e40, 0x016e7f, 0x01e900, 0x01e943)); } private static void populateCWKCF() { @@ -1349,7 +1376,7 @@ private static void populateCWKCF() { 0x0009dc, 0x0009dd, 0x0009df, 0x0009df, 0x000a33, 0x000a33, 0x000a36, 0x000a36, 0x000a59, 0x000a5b, 0x000a5e, 0x000a5e, 0x000b5c, 0x000b5d, 0x000e33, 0x000e33, 0x000eb3, 0x000eb3, 0x000edc, 0x000edd, 0x000f0c, 0x000f0c, 0x000f43, 0x000f43, 0x000f4d, 0x000f4d, 0x000f52, 0x000f52, 0x000f57, 0x000f57, 0x000f5c, 0x000f5c, 0x000f69, 0x000f69, 0x000f73, 0x000f73, 0x000f75, 0x000f79, 0x000f81, 0x000f81, 0x000f93, 0x000f93, 0x000f9d, 0x000f9d, 0x000fa2, 0x000fa2, 0x000fa7, 0x000fa7, 0x000fac, 0x000fac, 0x000fb9, - 0x000fb9, 0x0010a0, 0x0010c5, 0x0010c7, 0x0010c7, 0x0010cd, 0x0010cd, 0x0010fc, 0x0010fc, 0x00115f, 0x001160, 0x0013f8, 0x0013fd, 0x0017b4, 0x0017b5, 0x00180b, 0x00180e, + 0x000fb9, 0x0010a0, 0x0010c5, 0x0010c7, 0x0010c7, 0x0010cd, 0x0010cd, 0x0010fc, 0x0010fc, 0x00115f, 0x001160, 0x0013f8, 0x0013fd, 0x0017b4, 0x0017b5, 0x00180b, 0x00180f, 0x001c80, 0x001c88, 0x001c90, 0x001cba, 0x001cbd, 0x001cbf, 0x001d2c, 0x001d2e, 0x001d30, 0x001d3a, 0x001d3c, 0x001d4d, 0x001d4f, 0x001d6a, 0x001d78, 0x001d78, 0x001d9b, 0x001dbf, 0x001e00, 0x001e00, 0x001e02, 0x001e02, 0x001e04, 0x001e04, 0x001e06, 0x001e06, 0x001e08, 0x001e08, 0x001e0a, 0x001e0a, 0x001e0c, 0x001e0c, 0x001e0e, 0x001e0e, 0x001e10, 0x001e10, 0x001e12, 0x001e12, 0x001e14, 0x001e14, 0x001e16, 0x001e16, 0x001e18, 0x001e18, 0x001e1a, 0x001e1a, 0x001e1c, 0x001e1c, 0x001e1e, 0x001e1e, 0x001e20, @@ -1373,7 +1400,7 @@ private static void populateCWKCF() { 0x00203e, 0x00203e, 0x002047, 0x002049, 0x002057, 0x002057, 0x00205f, 0x002071, 0x002074, 0x00208e, 0x002090, 0x00209c, 0x0020a8, 0x0020a8, 0x002100, 0x002103, 0x002105, 0x002107, 0x002109, 0x002113, 0x002115, 0x002116, 0x002119, 0x00211d, 0x002120, 0x002122, 0x002124, 0x002124, 0x002126, 0x002126, 0x002128, 0x002128, 0x00212a, 0x00212d, 0x00212f, 0x002139, 0x00213b, 0x002140, 0x002145, 0x002149, 0x002150, 0x00217f, 0x002183, 0x002183, 0x002189, 0x002189, 0x00222c, 0x00222d, 0x00222f, 0x002230, 0x002329, - 0x00232a, 0x002460, 0x0024ea, 0x002a0c, 0x002a0c, 0x002a74, 0x002a76, 0x002adc, 0x002adc, 0x002c00, 0x002c2e, 0x002c60, 0x002c60, 0x002c62, 0x002c64, 0x002c67, 0x002c67, + 0x00232a, 0x002460, 0x0024ea, 0x002a0c, 0x002a0c, 0x002a74, 0x002a76, 0x002adc, 0x002adc, 0x002c00, 0x002c2f, 0x002c60, 0x002c60, 0x002c62, 0x002c64, 0x002c67, 0x002c67, 0x002c69, 0x002c69, 0x002c6b, 0x002c6b, 0x002c6d, 0x002c70, 0x002c72, 0x002c72, 0x002c75, 0x002c75, 0x002c7c, 0x002c80, 0x002c82, 0x002c82, 0x002c84, 0x002c84, 0x002c86, 0x002c86, 0x002c88, 0x002c88, 0x002c8a, 0x002c8a, 0x002c8c, 0x002c8c, 0x002c8e, 0x002c8e, 0x002c90, 0x002c90, 0x002c92, 0x002c92, 0x002c94, 0x002c94, 0x002c96, 0x002c96, 0x002c98, 0x002c98, 0x002c9a, 0x002c9a, 0x002c9c, 0x002c9c, 0x002c9e, 0x002c9e, 0x002ca0, 0x002ca0, 0x002ca2, 0x002ca2, 0x002ca4, 0x002ca4, 0x002ca6, 0x002ca6, 0x002ca8, @@ -1395,21 +1422,22 @@ private static void populateCWKCF() { 0x00a77d, 0x00a77e, 0x00a780, 0x00a780, 0x00a782, 0x00a782, 0x00a784, 0x00a784, 0x00a786, 0x00a786, 0x00a78b, 0x00a78b, 0x00a78d, 0x00a78d, 0x00a790, 0x00a790, 0x00a792, 0x00a792, 0x00a796, 0x00a796, 0x00a798, 0x00a798, 0x00a79a, 0x00a79a, 0x00a79c, 0x00a79c, 0x00a79e, 0x00a79e, 0x00a7a0, 0x00a7a0, 0x00a7a2, 0x00a7a2, 0x00a7a4, 0x00a7a4, 0x00a7a6, 0x00a7a6, 0x00a7a8, 0x00a7a8, 0x00a7aa, 0x00a7ae, 0x00a7b0, 0x00a7b4, 0x00a7b6, 0x00a7b6, 0x00a7b8, 0x00a7b8, 0x00a7ba, 0x00a7ba, 0x00a7bc, 0x00a7bc, 0x00a7be, - 0x00a7be, 0x00a7c2, 0x00a7c2, 0x00a7c4, 0x00a7c7, 0x00a7c9, 0x00a7c9, 0x00a7f5, 0x00a7f5, 0x00a7f8, 0x00a7f9, 0x00ab5c, 0x00ab5f, 0x00ab69, 0x00ab69, 0x00ab70, 0x00abbf, - 0x00f900, 0x00fa0d, 0x00fa10, 0x00fa10, 0x00fa12, 0x00fa12, 0x00fa15, 0x00fa1e, 0x00fa20, 0x00fa20, 0x00fa22, 0x00fa22, 0x00fa25, 0x00fa26, 0x00fa2a, 0x00fa6d, 0x00fa70, - 0x00fad9, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, 0x00fb1d, 0x00fb1d, 0x00fb1f, 0x00fb36, 0x00fb38, 0x00fb3c, 0x00fb3e, 0x00fb3e, 0x00fb40, 0x00fb41, 0x00fb43, 0x00fb44, - 0x00fb46, 0x00fbb1, 0x00fbd3, 0x00fd3d, 0x00fd50, 0x00fd8f, 0x00fd92, 0x00fdc7, 0x00fdf0, 0x00fdfc, 0x00fe00, 0x00fe19, 0x00fe30, 0x00fe44, 0x00fe47, 0x00fe52, 0x00fe54, - 0x00fe66, 0x00fe68, 0x00fe6b, 0x00fe70, 0x00fe72, 0x00fe74, 0x00fe74, 0x00fe76, 0x00fefc, 0x00feff, 0x00feff, 0x00ff01, 0x00ffbe, 0x00ffc2, 0x00ffc7, 0x00ffca, 0x00ffcf, - 0x00ffd2, 0x00ffd7, 0x00ffda, 0x00ffdc, 0x00ffe0, 0x00ffe6, 0x00ffe8, 0x00ffee, 0x00fff0, 0x00fff8, 0x010400, 0x010427, 0x0104b0, 0x0104d3, 0x010c80, 0x010cb2, 0x0118a0, - 0x0118bf, 0x016e40, 0x016e5f, 0x01bca0, 0x01bca3, 0x01d15e, 0x01d164, 0x01d173, 0x01d17a, 0x01d1bb, 0x01d1c0, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, - 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, - 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d7cb, - 0x01d7ce, 0x01d7ff, 0x01e900, 0x01e921, 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, - 0x01ee37, 0x01ee39, 0x01ee39, 0x01ee3b, 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, - 0x01ee54, 0x01ee54, 0x01ee57, 0x01ee57, 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, - 0x01ee6a, 0x01ee6c, 0x01ee72, 0x01ee74, 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, 0x01ee80, 0x01ee89, 0x01ee8b, 0x01ee9b, 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, - 0x01eeab, 0x01eebb, 0x01f100, 0x01f10a, 0x01f110, 0x01f12e, 0x01f130, 0x01f14f, 0x01f16a, 0x01f16c, 0x01f190, 0x01f190, 0x01f200, 0x01f202, 0x01f210, 0x01f23b, 0x01f240, - 0x01f248, 0x01f250, 0x01f251, 0x01fbf0, 0x01fbf9, 0x02f800, 0x02fa1d, 0x0e0000, 0x0e0fff)); + 0x00a7be, 0x00a7c0, 0x00a7c0, 0x00a7c2, 0x00a7c2, 0x00a7c4, 0x00a7c7, 0x00a7c9, 0x00a7c9, 0x00a7d0, 0x00a7d0, 0x00a7d6, 0x00a7d6, 0x00a7d8, 0x00a7d8, 0x00a7f2, 0x00a7f5, + 0x00a7f8, 0x00a7f9, 0x00ab5c, 0x00ab5f, 0x00ab69, 0x00ab69, 0x00ab70, 0x00abbf, 0x00f900, 0x00fa0d, 0x00fa10, 0x00fa10, 0x00fa12, 0x00fa12, 0x00fa15, 0x00fa1e, 0x00fa20, + 0x00fa20, 0x00fa22, 0x00fa22, 0x00fa25, 0x00fa26, 0x00fa2a, 0x00fa6d, 0x00fa70, 0x00fad9, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, 0x00fb1d, 0x00fb1d, 0x00fb1f, 0x00fb36, + 0x00fb38, 0x00fb3c, 0x00fb3e, 0x00fb3e, 0x00fb40, 0x00fb41, 0x00fb43, 0x00fb44, 0x00fb46, 0x00fbb1, 0x00fbd3, 0x00fd3d, 0x00fd50, 0x00fd8f, 0x00fd92, 0x00fdc7, 0x00fdf0, + 0x00fdfc, 0x00fe00, 0x00fe19, 0x00fe30, 0x00fe44, 0x00fe47, 0x00fe52, 0x00fe54, 0x00fe66, 0x00fe68, 0x00fe6b, 0x00fe70, 0x00fe72, 0x00fe74, 0x00fe74, 0x00fe76, 0x00fefc, + 0x00feff, 0x00feff, 0x00ff01, 0x00ffbe, 0x00ffc2, 0x00ffc7, 0x00ffca, 0x00ffcf, 0x00ffd2, 0x00ffd7, 0x00ffda, 0x00ffdc, 0x00ffe0, 0x00ffe6, 0x00ffe8, 0x00ffee, 0x00fff0, + 0x00fff8, 0x010400, 0x010427, 0x0104b0, 0x0104d3, 0x010570, 0x01057a, 0x01057c, 0x01058a, 0x01058c, 0x010592, 0x010594, 0x010595, 0x010781, 0x010785, 0x010787, 0x0107b0, + 0x0107b2, 0x0107ba, 0x010c80, 0x010cb2, 0x0118a0, 0x0118bf, 0x016e40, 0x016e5f, 0x01bca0, 0x01bca3, 0x01d15e, 0x01d164, 0x01d173, 0x01d17a, 0x01d1bb, 0x01d1c0, 0x01d400, + 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, + 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, + 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d7cb, 0x01d7ce, 0x01d7ff, 0x01e900, 0x01e921, 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, + 0x01ee27, 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, 0x01ee39, 0x01ee3b, 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, + 0x01ee4b, 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, 0x01ee57, 0x01ee57, 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, + 0x01ee61, 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, 0x01ee72, 0x01ee74, 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, 0x01ee80, 0x01ee89, 0x01ee8b, + 0x01ee9b, 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, 0x01f100, 0x01f10a, 0x01f110, 0x01f12e, 0x01f130, 0x01f14f, 0x01f16a, 0x01f16c, 0x01f190, 0x01f190, + 0x01f200, 0x01f202, 0x01f210, 0x01f23b, 0x01f240, 0x01f248, 0x01f250, 0x01f251, 0x01fbf0, 0x01fbf9, 0x02f800, 0x02fa1d, 0x0e0000, 0x0e0fff)); } private static void populateCWL() { @@ -1463,7 +1491,7 @@ private static void populateCWL() { 0x001efa, 0x001efa, 0x001efc, 0x001efc, 0x001efe, 0x001efe, 0x001f08, 0x001f0f, 0x001f18, 0x001f1d, 0x001f28, 0x001f2f, 0x001f38, 0x001f3f, 0x001f48, 0x001f4d, 0x001f59, 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f5f, 0x001f68, 0x001f6f, 0x001f88, 0x001f8f, 0x001f98, 0x001f9f, 0x001fa8, 0x001faf, 0x001fb8, 0x001fbc, 0x001fc8, 0x001fcc, 0x001fd8, 0x001fdb, 0x001fe8, 0x001fec, 0x001ff8, 0x001ffc, 0x002126, 0x002126, 0x00212a, 0x00212b, 0x002132, 0x002132, 0x002160, 0x00216f, 0x002183, - 0x002183, 0x0024b6, 0x0024cf, 0x002c00, 0x002c2e, 0x002c60, 0x002c60, 0x002c62, 0x002c64, 0x002c67, 0x002c67, 0x002c69, 0x002c69, 0x002c6b, 0x002c6b, 0x002c6d, 0x002c70, + 0x002183, 0x0024b6, 0x0024cf, 0x002c00, 0x002c2f, 0x002c60, 0x002c60, 0x002c62, 0x002c64, 0x002c67, 0x002c67, 0x002c69, 0x002c69, 0x002c6b, 0x002c6b, 0x002c6d, 0x002c70, 0x002c72, 0x002c72, 0x002c75, 0x002c75, 0x002c7e, 0x002c80, 0x002c82, 0x002c82, 0x002c84, 0x002c84, 0x002c86, 0x002c86, 0x002c88, 0x002c88, 0x002c8a, 0x002c8a, 0x002c8c, 0x002c8c, 0x002c8e, 0x002c8e, 0x002c90, 0x002c90, 0x002c92, 0x002c92, 0x002c94, 0x002c94, 0x002c96, 0x002c96, 0x002c98, 0x002c98, 0x002c9a, 0x002c9a, 0x002c9c, 0x002c9c, 0x002c9e, 0x002c9e, 0x002ca0, 0x002ca0, 0x002ca2, 0x002ca2, 0x002ca4, 0x002ca4, 0x002ca6, 0x002ca6, 0x002ca8, 0x002ca8, 0x002caa, 0x002caa, 0x002cac, 0x002cac, 0x002cae, @@ -1482,8 +1510,9 @@ private static void populateCWL() { 0x00a76a, 0x00a76c, 0x00a76c, 0x00a76e, 0x00a76e, 0x00a779, 0x00a779, 0x00a77b, 0x00a77b, 0x00a77d, 0x00a77e, 0x00a780, 0x00a780, 0x00a782, 0x00a782, 0x00a784, 0x00a784, 0x00a786, 0x00a786, 0x00a78b, 0x00a78b, 0x00a78d, 0x00a78d, 0x00a790, 0x00a790, 0x00a792, 0x00a792, 0x00a796, 0x00a796, 0x00a798, 0x00a798, 0x00a79a, 0x00a79a, 0x00a79c, 0x00a79c, 0x00a79e, 0x00a79e, 0x00a7a0, 0x00a7a0, 0x00a7a2, 0x00a7a2, 0x00a7a4, 0x00a7a4, 0x00a7a6, 0x00a7a6, 0x00a7a8, 0x00a7a8, 0x00a7aa, 0x00a7ae, 0x00a7b0, 0x00a7b4, - 0x00a7b6, 0x00a7b6, 0x00a7b8, 0x00a7b8, 0x00a7ba, 0x00a7ba, 0x00a7bc, 0x00a7bc, 0x00a7be, 0x00a7be, 0x00a7c2, 0x00a7c2, 0x00a7c4, 0x00a7c7, 0x00a7c9, 0x00a7c9, 0x00a7f5, - 0x00a7f5, 0x00ff21, 0x00ff3a, 0x010400, 0x010427, 0x0104b0, 0x0104d3, 0x010c80, 0x010cb2, 0x0118a0, 0x0118bf, 0x016e40, 0x016e5f, 0x01e900, 0x01e921)); + 0x00a7b6, 0x00a7b6, 0x00a7b8, 0x00a7b8, 0x00a7ba, 0x00a7ba, 0x00a7bc, 0x00a7bc, 0x00a7be, 0x00a7be, 0x00a7c0, 0x00a7c0, 0x00a7c2, 0x00a7c2, 0x00a7c4, 0x00a7c7, 0x00a7c9, + 0x00a7c9, 0x00a7d0, 0x00a7d0, 0x00a7d6, 0x00a7d6, 0x00a7d8, 0x00a7d8, 0x00a7f5, 0x00a7f5, 0x00ff21, 0x00ff3a, 0x010400, 0x010427, 0x0104b0, 0x0104d3, 0x010570, 0x01057a, + 0x01057c, 0x01058a, 0x01058c, 0x010592, 0x010594, 0x010595, 0x010c80, 0x010cb2, 0x0118a0, 0x0118bf, 0x016e40, 0x016e5f, 0x01e900, 0x01e921)); } private static void populateCWT() { @@ -1538,7 +1567,7 @@ private static void populateCWT() { 0x001ef1, 0x001ef3, 0x001ef3, 0x001ef5, 0x001ef5, 0x001ef7, 0x001ef7, 0x001ef9, 0x001ef9, 0x001efb, 0x001efb, 0x001efd, 0x001efd, 0x001eff, 0x001f07, 0x001f10, 0x001f15, 0x001f20, 0x001f27, 0x001f30, 0x001f37, 0x001f40, 0x001f45, 0x001f50, 0x001f57, 0x001f60, 0x001f67, 0x001f70, 0x001f7d, 0x001f80, 0x001f87, 0x001f90, 0x001f97, 0x001fa0, 0x001fa7, 0x001fb0, 0x001fb4, 0x001fb6, 0x001fb7, 0x001fbe, 0x001fbe, 0x001fc2, 0x001fc4, 0x001fc6, 0x001fc7, 0x001fd0, 0x001fd3, 0x001fd6, 0x001fd7, 0x001fe0, 0x001fe7, - 0x001ff2, 0x001ff4, 0x001ff6, 0x001ff7, 0x00214e, 0x00214e, 0x002170, 0x00217f, 0x002184, 0x002184, 0x0024d0, 0x0024e9, 0x002c30, 0x002c5e, 0x002c61, 0x002c61, 0x002c65, + 0x001ff2, 0x001ff4, 0x001ff6, 0x001ff7, 0x00214e, 0x00214e, 0x002170, 0x00217f, 0x002184, 0x002184, 0x0024d0, 0x0024e9, 0x002c30, 0x002c5f, 0x002c61, 0x002c61, 0x002c65, 0x002c66, 0x002c68, 0x002c68, 0x002c6a, 0x002c6a, 0x002c6c, 0x002c6c, 0x002c73, 0x002c73, 0x002c76, 0x002c76, 0x002c81, 0x002c81, 0x002c83, 0x002c83, 0x002c85, 0x002c85, 0x002c87, 0x002c87, 0x002c89, 0x002c89, 0x002c8b, 0x002c8b, 0x002c8d, 0x002c8d, 0x002c8f, 0x002c8f, 0x002c91, 0x002c91, 0x002c93, 0x002c93, 0x002c95, 0x002c95, 0x002c97, 0x002c97, 0x002c99, 0x002c99, 0x002c9b, 0x002c9b, 0x002c9d, 0x002c9d, 0x002c9f, 0x002c9f, 0x002ca1, 0x002ca1, 0x002ca3, 0x002ca3, 0x002ca5, 0x002ca5, 0x002ca7, 0x002ca7, @@ -1558,8 +1587,9 @@ private static void populateCWT() { 0x00a76f, 0x00a77a, 0x00a77a, 0x00a77c, 0x00a77c, 0x00a77f, 0x00a77f, 0x00a781, 0x00a781, 0x00a783, 0x00a783, 0x00a785, 0x00a785, 0x00a787, 0x00a787, 0x00a78c, 0x00a78c, 0x00a791, 0x00a791, 0x00a793, 0x00a794, 0x00a797, 0x00a797, 0x00a799, 0x00a799, 0x00a79b, 0x00a79b, 0x00a79d, 0x00a79d, 0x00a79f, 0x00a79f, 0x00a7a1, 0x00a7a1, 0x00a7a3, 0x00a7a3, 0x00a7a5, 0x00a7a5, 0x00a7a7, 0x00a7a7, 0x00a7a9, 0x00a7a9, 0x00a7b5, 0x00a7b5, 0x00a7b7, 0x00a7b7, 0x00a7b9, 0x00a7b9, 0x00a7bb, 0x00a7bb, 0x00a7bd, 0x00a7bd, - 0x00a7bf, 0x00a7bf, 0x00a7c3, 0x00a7c3, 0x00a7c8, 0x00a7c8, 0x00a7ca, 0x00a7ca, 0x00a7f6, 0x00a7f6, 0x00ab53, 0x00ab53, 0x00ab70, 0x00abbf, 0x00fb00, 0x00fb06, 0x00fb13, - 0x00fb17, 0x00ff41, 0x00ff5a, 0x010428, 0x01044f, 0x0104d8, 0x0104fb, 0x010cc0, 0x010cf2, 0x0118c0, 0x0118df, 0x016e60, 0x016e7f, 0x01e922, 0x01e943)); + 0x00a7bf, 0x00a7bf, 0x00a7c1, 0x00a7c1, 0x00a7c3, 0x00a7c3, 0x00a7c8, 0x00a7c8, 0x00a7ca, 0x00a7ca, 0x00a7d1, 0x00a7d1, 0x00a7d7, 0x00a7d7, 0x00a7d9, 0x00a7d9, 0x00a7f6, + 0x00a7f6, 0x00ab53, 0x00ab53, 0x00ab70, 0x00abbf, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, 0x00ff41, 0x00ff5a, 0x010428, 0x01044f, 0x0104d8, 0x0104fb, 0x010597, 0x0105a1, + 0x0105a3, 0x0105b1, 0x0105b3, 0x0105b9, 0x0105bb, 0x0105bc, 0x010cc0, 0x010cf2, 0x0118c0, 0x0118df, 0x016e60, 0x016e7f, 0x01e922, 0x01e943)); } private static void populateCWU() { @@ -1614,7 +1644,7 @@ private static void populateCWU() { 0x001eef, 0x001ef1, 0x001ef1, 0x001ef3, 0x001ef3, 0x001ef5, 0x001ef5, 0x001ef7, 0x001ef7, 0x001ef9, 0x001ef9, 0x001efb, 0x001efb, 0x001efd, 0x001efd, 0x001eff, 0x001f07, 0x001f10, 0x001f15, 0x001f20, 0x001f27, 0x001f30, 0x001f37, 0x001f40, 0x001f45, 0x001f50, 0x001f57, 0x001f60, 0x001f67, 0x001f70, 0x001f7d, 0x001f80, 0x001fb4, 0x001fb6, 0x001fb7, 0x001fbc, 0x001fbc, 0x001fbe, 0x001fbe, 0x001fc2, 0x001fc4, 0x001fc6, 0x001fc7, 0x001fcc, 0x001fcc, 0x001fd0, 0x001fd3, 0x001fd6, 0x001fd7, 0x001fe0, 0x001fe7, - 0x001ff2, 0x001ff4, 0x001ff6, 0x001ff7, 0x001ffc, 0x001ffc, 0x00214e, 0x00214e, 0x002170, 0x00217f, 0x002184, 0x002184, 0x0024d0, 0x0024e9, 0x002c30, 0x002c5e, 0x002c61, + 0x001ff2, 0x001ff4, 0x001ff6, 0x001ff7, 0x001ffc, 0x001ffc, 0x00214e, 0x00214e, 0x002170, 0x00217f, 0x002184, 0x002184, 0x0024d0, 0x0024e9, 0x002c30, 0x002c5f, 0x002c61, 0x002c61, 0x002c65, 0x002c66, 0x002c68, 0x002c68, 0x002c6a, 0x002c6a, 0x002c6c, 0x002c6c, 0x002c73, 0x002c73, 0x002c76, 0x002c76, 0x002c81, 0x002c81, 0x002c83, 0x002c83, 0x002c85, 0x002c85, 0x002c87, 0x002c87, 0x002c89, 0x002c89, 0x002c8b, 0x002c8b, 0x002c8d, 0x002c8d, 0x002c8f, 0x002c8f, 0x002c91, 0x002c91, 0x002c93, 0x002c93, 0x002c95, 0x002c95, 0x002c97, 0x002c97, 0x002c99, 0x002c99, 0x002c9b, 0x002c9b, 0x002c9d, 0x002c9d, 0x002c9f, 0x002c9f, 0x002ca1, 0x002ca1, 0x002ca3, 0x002ca3, 0x002ca5, 0x002ca5, @@ -1634,8 +1664,9 @@ private static void populateCWU() { 0x00a76d, 0x00a76f, 0x00a76f, 0x00a77a, 0x00a77a, 0x00a77c, 0x00a77c, 0x00a77f, 0x00a77f, 0x00a781, 0x00a781, 0x00a783, 0x00a783, 0x00a785, 0x00a785, 0x00a787, 0x00a787, 0x00a78c, 0x00a78c, 0x00a791, 0x00a791, 0x00a793, 0x00a794, 0x00a797, 0x00a797, 0x00a799, 0x00a799, 0x00a79b, 0x00a79b, 0x00a79d, 0x00a79d, 0x00a79f, 0x00a79f, 0x00a7a1, 0x00a7a1, 0x00a7a3, 0x00a7a3, 0x00a7a5, 0x00a7a5, 0x00a7a7, 0x00a7a7, 0x00a7a9, 0x00a7a9, 0x00a7b5, 0x00a7b5, 0x00a7b7, 0x00a7b7, 0x00a7b9, 0x00a7b9, 0x00a7bb, 0x00a7bb, - 0x00a7bd, 0x00a7bd, 0x00a7bf, 0x00a7bf, 0x00a7c3, 0x00a7c3, 0x00a7c8, 0x00a7c8, 0x00a7ca, 0x00a7ca, 0x00a7f6, 0x00a7f6, 0x00ab53, 0x00ab53, 0x00ab70, 0x00abbf, 0x00fb00, - 0x00fb06, 0x00fb13, 0x00fb17, 0x00ff41, 0x00ff5a, 0x010428, 0x01044f, 0x0104d8, 0x0104fb, 0x010cc0, 0x010cf2, 0x0118c0, 0x0118df, 0x016e60, 0x016e7f, 0x01e922, 0x01e943)); + 0x00a7bd, 0x00a7bd, 0x00a7bf, 0x00a7bf, 0x00a7c1, 0x00a7c1, 0x00a7c3, 0x00a7c3, 0x00a7c8, 0x00a7c8, 0x00a7ca, 0x00a7ca, 0x00a7d1, 0x00a7d1, 0x00a7d7, 0x00a7d7, 0x00a7d9, + 0x00a7d9, 0x00a7f6, 0x00a7f6, 0x00ab53, 0x00ab53, 0x00ab70, 0x00abbf, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, 0x00ff41, 0x00ff5a, 0x010428, 0x01044f, 0x0104d8, 0x0104fb, + 0x010597, 0x0105a1, 0x0105a3, 0x0105b1, 0x0105b3, 0x0105b9, 0x0105bb, 0x0105bc, 0x010cc0, 0x010cf2, 0x0118c0, 0x0118df, 0x016e60, 0x016e7f, 0x01e922, 0x01e943)); } private static void populateCASED() { @@ -1648,19 +1679,21 @@ private static void populateCASED() { 0x001fbe, 0x001fbe, 0x001fc2, 0x001fc4, 0x001fc6, 0x001fcc, 0x001fd0, 0x001fd3, 0x001fd6, 0x001fdb, 0x001fe0, 0x001fec, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ffc, 0x002071, 0x002071, 0x00207f, 0x00207f, 0x002090, 0x00209c, 0x002102, 0x002102, 0x002107, 0x002107, 0x00210a, 0x002113, 0x002115, 0x002115, 0x002119, 0x00211d, 0x002124, 0x002124, 0x002126, 0x002126, 0x002128, 0x002128, 0x00212a, 0x00212d, 0x00212f, 0x002134, 0x002139, 0x002139, 0x00213c, 0x00213f, 0x002145, 0x002149, 0x00214e, 0x00214e, 0x002160, - 0x00217f, 0x002183, 0x002184, 0x0024b6, 0x0024e9, 0x002c00, 0x002c2e, 0x002c30, 0x002c5e, 0x002c60, 0x002ce4, 0x002ceb, 0x002cee, 0x002cf2, 0x002cf3, 0x002d00, 0x002d25, - 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, 0x00a640, 0x00a66d, 0x00a680, 0x00a69d, 0x00a722, 0x00a787, 0x00a78b, 0x00a78e, 0x00a790, 0x00a7bf, 0x00a7c2, 0x00a7ca, 0x00a7f5, + 0x00217f, 0x002183, 0x002184, 0x0024b6, 0x0024e9, 0x002c00, 0x002ce4, 0x002ceb, 0x002cee, 0x002cf2, 0x002cf3, 0x002d00, 0x002d25, 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, + 0x00a640, 0x00a66d, 0x00a680, 0x00a69d, 0x00a722, 0x00a787, 0x00a78b, 0x00a78e, 0x00a790, 0x00a7ca, 0x00a7d0, 0x00a7d1, 0x00a7d3, 0x00a7d3, 0x00a7d5, 0x00a7d9, 0x00a7f5, 0x00a7f6, 0x00a7f8, 0x00a7fa, 0x00ab30, 0x00ab5a, 0x00ab5c, 0x00ab68, 0x00ab70, 0x00abbf, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, 0x00ff21, 0x00ff3a, 0x00ff41, 0x00ff5a, - 0x010400, 0x01044f, 0x0104b0, 0x0104d3, 0x0104d8, 0x0104fb, 0x010c80, 0x010cb2, 0x010cc0, 0x010cf2, 0x0118a0, 0x0118df, 0x016e40, 0x016e7f, 0x01d400, 0x01d454, 0x01d456, - 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, - 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, - 0x01d6a5, 0x01d6a8, 0x01d6c0, 0x01d6c2, 0x01d6da, 0x01d6dc, 0x01d6fa, 0x01d6fc, 0x01d714, 0x01d716, 0x01d734, 0x01d736, 0x01d74e, 0x01d750, 0x01d76e, 0x01d770, 0x01d788, - 0x01d78a, 0x01d7a8, 0x01d7aa, 0x01d7c2, 0x01d7c4, 0x01d7cb, 0x01e900, 0x01e943, 0x01f130, 0x01f149, 0x01f150, 0x01f169, 0x01f170, 0x01f189)); + 0x010400, 0x01044f, 0x0104b0, 0x0104d3, 0x0104d8, 0x0104fb, 0x010570, 0x01057a, 0x01057c, 0x01058a, 0x01058c, 0x010592, 0x010594, 0x010595, 0x010597, 0x0105a1, 0x0105a3, + 0x0105b1, 0x0105b3, 0x0105b9, 0x0105bb, 0x0105bc, 0x010780, 0x010780, 0x010783, 0x010785, 0x010787, 0x0107b0, 0x0107b2, 0x0107ba, 0x010c80, 0x010cb2, 0x010cc0, 0x010cf2, + 0x0118a0, 0x0118df, 0x016e40, 0x016e7f, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, + 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, + 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d6c0, 0x01d6c2, 0x01d6da, 0x01d6dc, 0x01d6fa, 0x01d6fc, 0x01d714, 0x01d716, + 0x01d734, 0x01d736, 0x01d74e, 0x01d750, 0x01d76e, 0x01d770, 0x01d788, 0x01d78a, 0x01d7a8, 0x01d7aa, 0x01d7c2, 0x01d7c4, 0x01d7cb, 0x01df00, 0x01df09, 0x01df0b, 0x01df1e, + 0x01e900, 0x01e943, 0x01f130, 0x01f149, 0x01f150, 0x01f169, 0x01f170, 0x01f189)); } private static void populateDI() { SET_ENCODINGS.put("DI", - CodePointSet.createNoDedup(0x0000ad, 0x0000ad, 0x00034f, 0x00034f, 0x00061c, 0x00061c, 0x00115f, 0x001160, 0x0017b4, 0x0017b5, 0x00180b, 0x00180e, 0x00200b, 0x00200f, 0x00202a, + CodePointSet.createNoDedup(0x0000ad, 0x0000ad, 0x00034f, 0x00034f, 0x00061c, 0x00061c, 0x00115f, 0x001160, 0x0017b4, 0x0017b5, 0x00180b, 0x00180f, 0x00200b, 0x00200f, 0x00202a, 0x00202e, 0x002060, 0x00206f, 0x003164, 0x003164, 0x00fe00, 0x00fe0f, 0x00feff, 0x00feff, 0x00ffa0, 0x00ffa0, 0x00fff0, 0x00fff8, 0x01bca0, 0x01bca3, 0x01d173, 0x01d17a, 0x0e0000, 0x0e0fff)); } @@ -1668,8 +1701,8 @@ private static void populateDI() { private static void populateDASH() { SET_ENCODINGS.put("Dash", CodePointSet.createNoDedup(0x00002d, 0x00002d, 0x00058a, 0x00058a, 0x0005be, 0x0005be, 0x001400, 0x001400, 0x001806, 0x001806, 0x002010, 0x002015, 0x002053, 0x002053, 0x00207b, - 0x00207b, 0x00208b, 0x00208b, 0x002212, 0x002212, 0x002e17, 0x002e17, 0x002e1a, 0x002e1a, 0x002e3a, 0x002e3b, 0x002e40, 0x002e40, 0x00301c, 0x00301c, 0x003030, - 0x003030, 0x0030a0, 0x0030a0, 0x00fe31, 0x00fe32, 0x00fe58, 0x00fe58, 0x00fe63, 0x00fe63, 0x00ff0d, 0x00ff0d, 0x010ead, 0x010ead)); + 0x00207b, 0x00208b, 0x00208b, 0x002212, 0x002212, 0x002e17, 0x002e17, 0x002e1a, 0x002e1a, 0x002e3a, 0x002e3b, 0x002e40, 0x002e40, 0x002e5d, 0x002e5d, 0x00301c, + 0x00301c, 0x003030, 0x003030, 0x0030a0, 0x0030a0, 0x00fe31, 0x00fe32, 0x00fe58, 0x00fe58, 0x00fe63, 0x00fe63, 0x00ff0d, 0x00ff0d, 0x010ead, 0x010ead)); } private static void populateDEP() { @@ -1681,33 +1714,34 @@ private static void populateDIA() { SET_ENCODINGS.put("Dia", CodePointSet.createNoDedup(0x00005e, 0x00005e, 0x000060, 0x000060, 0x0000a8, 0x0000a8, 0x0000af, 0x0000af, 0x0000b4, 0x0000b4, 0x0000b7, 0x0000b8, 0x0002b0, 0x00034e, 0x000350, 0x000357, 0x00035d, 0x000362, 0x000374, 0x000375, 0x00037a, 0x00037a, 0x000384, 0x000385, 0x000483, 0x000487, 0x000559, 0x000559, 0x000591, 0x0005a1, 0x0005a3, 0x0005bd, 0x0005bf, 0x0005bf, 0x0005c1, 0x0005c2, 0x0005c4, 0x0005c4, 0x00064b, 0x000652, 0x000657, 0x000658, 0x0006df, 0x0006e0, 0x0006e5, 0x0006e6, 0x0006ea, 0x0006ec, - 0x000730, 0x00074a, 0x0007a6, 0x0007b0, 0x0007eb, 0x0007f5, 0x000818, 0x000819, 0x0008e3, 0x0008fe, 0x00093c, 0x00093c, 0x00094d, 0x00094d, 0x000951, 0x000954, 0x000971, - 0x000971, 0x0009bc, 0x0009bc, 0x0009cd, 0x0009cd, 0x000a3c, 0x000a3c, 0x000a4d, 0x000a4d, 0x000abc, 0x000abc, 0x000acd, 0x000acd, 0x000afd, 0x000aff, 0x000b3c, 0x000b3c, - 0x000b4d, 0x000b4d, 0x000b55, 0x000b55, 0x000bcd, 0x000bcd, 0x000c4d, 0x000c4d, 0x000cbc, 0x000cbc, 0x000ccd, 0x000ccd, 0x000d3b, 0x000d3c, 0x000d4d, 0x000d4d, 0x000dca, - 0x000dca, 0x000e47, 0x000e4c, 0x000e4e, 0x000e4e, 0x000eba, 0x000eba, 0x000ec8, 0x000ecc, 0x000f18, 0x000f19, 0x000f35, 0x000f35, 0x000f37, 0x000f37, 0x000f39, 0x000f39, - 0x000f3e, 0x000f3f, 0x000f82, 0x000f84, 0x000f86, 0x000f87, 0x000fc6, 0x000fc6, 0x001037, 0x001037, 0x001039, 0x00103a, 0x001063, 0x001064, 0x001069, 0x00106d, 0x001087, - 0x00108d, 0x00108f, 0x00108f, 0x00109a, 0x00109b, 0x00135d, 0x00135f, 0x0017c9, 0x0017d3, 0x0017dd, 0x0017dd, 0x001939, 0x00193b, 0x001a75, 0x001a7c, 0x001a7f, 0x001a7f, - 0x001ab0, 0x001abd, 0x001b34, 0x001b34, 0x001b44, 0x001b44, 0x001b6b, 0x001b73, 0x001baa, 0x001bab, 0x001c36, 0x001c37, 0x001c78, 0x001c7d, 0x001cd0, 0x001ce8, 0x001ced, - 0x001ced, 0x001cf4, 0x001cf4, 0x001cf7, 0x001cf9, 0x001d2c, 0x001d6a, 0x001dc4, 0x001dcf, 0x001df5, 0x001df9, 0x001dfd, 0x001dff, 0x001fbd, 0x001fbd, 0x001fbf, 0x001fc1, - 0x001fcd, 0x001fcf, 0x001fdd, 0x001fdf, 0x001fed, 0x001fef, 0x001ffd, 0x001ffe, 0x002cef, 0x002cf1, 0x002e2f, 0x002e2f, 0x00302a, 0x00302f, 0x003099, 0x00309c, 0x0030fc, - 0x0030fc, 0x00a66f, 0x00a66f, 0x00a67c, 0x00a67d, 0x00a67f, 0x00a67f, 0x00a69c, 0x00a69d, 0x00a6f0, 0x00a6f1, 0x00a700, 0x00a721, 0x00a788, 0x00a78a, 0x00a7f8, 0x00a7f9, - 0x00a8c4, 0x00a8c4, 0x00a8e0, 0x00a8f1, 0x00a92b, 0x00a92e, 0x00a953, 0x00a953, 0x00a9b3, 0x00a9b3, 0x00a9c0, 0x00a9c0, 0x00a9e5, 0x00a9e5, 0x00aa7b, 0x00aa7d, 0x00aabf, - 0x00aac2, 0x00aaf6, 0x00aaf6, 0x00ab5b, 0x00ab5f, 0x00ab69, 0x00ab6b, 0x00abec, 0x00abed, 0x00fb1e, 0x00fb1e, 0x00fe20, 0x00fe2f, 0x00ff3e, 0x00ff3e, 0x00ff40, 0x00ff40, - 0x00ff70, 0x00ff70, 0x00ff9e, 0x00ff9f, 0x00ffe3, 0x00ffe3, 0x0102e0, 0x0102e0, 0x010ae5, 0x010ae6, 0x010d22, 0x010d27, 0x010f46, 0x010f50, 0x0110b9, 0x0110ba, 0x011133, - 0x011134, 0x011173, 0x011173, 0x0111c0, 0x0111c0, 0x0111ca, 0x0111cc, 0x011235, 0x011236, 0x0112e9, 0x0112ea, 0x01133c, 0x01133c, 0x01134d, 0x01134d, 0x011366, 0x01136c, - 0x011370, 0x011374, 0x011442, 0x011442, 0x011446, 0x011446, 0x0114c2, 0x0114c3, 0x0115bf, 0x0115c0, 0x01163f, 0x01163f, 0x0116b6, 0x0116b7, 0x01172b, 0x01172b, 0x011839, - 0x01183a, 0x01193d, 0x01193e, 0x011943, 0x011943, 0x0119e0, 0x0119e0, 0x011a34, 0x011a34, 0x011a47, 0x011a47, 0x011a99, 0x011a99, 0x011c3f, 0x011c3f, 0x011d42, 0x011d42, - 0x011d44, 0x011d45, 0x011d97, 0x011d97, 0x016af0, 0x016af4, 0x016b30, 0x016b36, 0x016f8f, 0x016f9f, 0x016ff0, 0x016ff1, 0x01d167, 0x01d169, 0x01d16d, 0x01d172, 0x01d17b, - 0x01d182, 0x01d185, 0x01d18b, 0x01d1aa, 0x01d1ad, 0x01e130, 0x01e136, 0x01e2ec, 0x01e2ef, 0x01e8d0, 0x01e8d6, 0x01e944, 0x01e946, 0x01e948, 0x01e94a)); + 0x000730, 0x00074a, 0x0007a6, 0x0007b0, 0x0007eb, 0x0007f5, 0x000818, 0x000819, 0x000898, 0x00089f, 0x0008c9, 0x0008d2, 0x0008e3, 0x0008fe, 0x00093c, 0x00093c, 0x00094d, + 0x00094d, 0x000951, 0x000954, 0x000971, 0x000971, 0x0009bc, 0x0009bc, 0x0009cd, 0x0009cd, 0x000a3c, 0x000a3c, 0x000a4d, 0x000a4d, 0x000abc, 0x000abc, 0x000acd, 0x000acd, + 0x000afd, 0x000aff, 0x000b3c, 0x000b3c, 0x000b4d, 0x000b4d, 0x000b55, 0x000b55, 0x000bcd, 0x000bcd, 0x000c3c, 0x000c3c, 0x000c4d, 0x000c4d, 0x000cbc, 0x000cbc, 0x000ccd, + 0x000ccd, 0x000d3b, 0x000d3c, 0x000d4d, 0x000d4d, 0x000dca, 0x000dca, 0x000e47, 0x000e4c, 0x000e4e, 0x000e4e, 0x000eba, 0x000eba, 0x000ec8, 0x000ecc, 0x000f18, 0x000f19, + 0x000f35, 0x000f35, 0x000f37, 0x000f37, 0x000f39, 0x000f39, 0x000f3e, 0x000f3f, 0x000f82, 0x000f84, 0x000f86, 0x000f87, 0x000fc6, 0x000fc6, 0x001037, 0x001037, 0x001039, + 0x00103a, 0x001063, 0x001064, 0x001069, 0x00106d, 0x001087, 0x00108d, 0x00108f, 0x00108f, 0x00109a, 0x00109b, 0x00135d, 0x00135f, 0x001714, 0x001715, 0x0017c9, 0x0017d3, + 0x0017dd, 0x0017dd, 0x001939, 0x00193b, 0x001a75, 0x001a7c, 0x001a7f, 0x001a7f, 0x001ab0, 0x001abe, 0x001ac1, 0x001acb, 0x001b34, 0x001b34, 0x001b44, 0x001b44, 0x001b6b, + 0x001b73, 0x001baa, 0x001bab, 0x001c36, 0x001c37, 0x001c78, 0x001c7d, 0x001cd0, 0x001ce8, 0x001ced, 0x001ced, 0x001cf4, 0x001cf4, 0x001cf7, 0x001cf9, 0x001d2c, 0x001d6a, + 0x001dc4, 0x001dcf, 0x001df5, 0x001dff, 0x001fbd, 0x001fbd, 0x001fbf, 0x001fc1, 0x001fcd, 0x001fcf, 0x001fdd, 0x001fdf, 0x001fed, 0x001fef, 0x001ffd, 0x001ffe, 0x002cef, + 0x002cf1, 0x002e2f, 0x002e2f, 0x00302a, 0x00302f, 0x003099, 0x00309c, 0x0030fc, 0x0030fc, 0x00a66f, 0x00a66f, 0x00a67c, 0x00a67d, 0x00a67f, 0x00a67f, 0x00a69c, 0x00a69d, + 0x00a6f0, 0x00a6f1, 0x00a700, 0x00a721, 0x00a788, 0x00a78a, 0x00a7f8, 0x00a7f9, 0x00a8c4, 0x00a8c4, 0x00a8e0, 0x00a8f1, 0x00a92b, 0x00a92e, 0x00a953, 0x00a953, 0x00a9b3, + 0x00a9b3, 0x00a9c0, 0x00a9c0, 0x00a9e5, 0x00a9e5, 0x00aa7b, 0x00aa7d, 0x00aabf, 0x00aac2, 0x00aaf6, 0x00aaf6, 0x00ab5b, 0x00ab5f, 0x00ab69, 0x00ab6b, 0x00abec, 0x00abed, + 0x00fb1e, 0x00fb1e, 0x00fe20, 0x00fe2f, 0x00ff3e, 0x00ff3e, 0x00ff40, 0x00ff40, 0x00ff70, 0x00ff70, 0x00ff9e, 0x00ff9f, 0x00ffe3, 0x00ffe3, 0x0102e0, 0x0102e0, 0x010780, + 0x010785, 0x010787, 0x0107b0, 0x0107b2, 0x0107ba, 0x010ae5, 0x010ae6, 0x010d22, 0x010d27, 0x010f46, 0x010f50, 0x010f82, 0x010f85, 0x011046, 0x011046, 0x011070, 0x011070, + 0x0110b9, 0x0110ba, 0x011133, 0x011134, 0x011173, 0x011173, 0x0111c0, 0x0111c0, 0x0111ca, 0x0111cc, 0x011235, 0x011236, 0x0112e9, 0x0112ea, 0x01133c, 0x01133c, 0x01134d, + 0x01134d, 0x011366, 0x01136c, 0x011370, 0x011374, 0x011442, 0x011442, 0x011446, 0x011446, 0x0114c2, 0x0114c3, 0x0115bf, 0x0115c0, 0x01163f, 0x01163f, 0x0116b6, 0x0116b7, + 0x01172b, 0x01172b, 0x011839, 0x01183a, 0x01193d, 0x01193e, 0x011943, 0x011943, 0x0119e0, 0x0119e0, 0x011a34, 0x011a34, 0x011a47, 0x011a47, 0x011a99, 0x011a99, 0x011c3f, + 0x011c3f, 0x011d42, 0x011d42, 0x011d44, 0x011d45, 0x011d97, 0x011d97, 0x016af0, 0x016af4, 0x016b30, 0x016b36, 0x016f8f, 0x016f9f, 0x016ff0, 0x016ff1, 0x01aff0, 0x01aff3, + 0x01aff5, 0x01affb, 0x01affd, 0x01affe, 0x01cf00, 0x01cf2d, 0x01cf30, 0x01cf46, 0x01d167, 0x01d169, 0x01d16d, 0x01d172, 0x01d17b, 0x01d182, 0x01d185, 0x01d18b, 0x01d1aa, + 0x01d1ad, 0x01e130, 0x01e136, 0x01e2ae, 0x01e2ae, 0x01e2ec, 0x01e2ef, 0x01e8d0, 0x01e8d6, 0x01e944, 0x01e946, 0x01e948, 0x01e94a)); } private static void populateEBASE() { - SET_ENCODINGS.put("EBase", - CodePointSet.createNoDedup(0x00261d, 0x00261d, 0x0026f9, 0x0026f9, 0x00270a, 0x00270d, 0x01f385, 0x01f385, 0x01f3c2, 0x01f3c4, 0x01f3c7, 0x01f3c7, 0x01f3ca, 0x01f3cc, 0x01f442, - 0x01f443, 0x01f446, 0x01f450, 0x01f466, 0x01f478, 0x01f47c, 0x01f47c, 0x01f481, 0x01f483, 0x01f485, 0x01f487, 0x01f48f, 0x01f48f, 0x01f491, 0x01f491, 0x01f4aa, - 0x01f4aa, 0x01f574, 0x01f575, 0x01f57a, 0x01f57a, 0x01f590, 0x01f590, 0x01f595, 0x01f596, 0x01f645, 0x01f647, 0x01f64b, 0x01f64f, 0x01f6a3, 0x01f6a3, 0x01f6b4, - 0x01f6b6, 0x01f6c0, 0x01f6c0, 0x01f6cc, 0x01f6cc, 0x01f90c, 0x01f90c, 0x01f90f, 0x01f90f, 0x01f918, 0x01f91f, 0x01f926, 0x01f926, 0x01f930, 0x01f939, 0x01f93c, - 0x01f93e, 0x01f977, 0x01f977, 0x01f9b5, 0x01f9b6, 0x01f9b8, 0x01f9b9, 0x01f9bb, 0x01f9bb, 0x01f9cd, 0x01f9cf, 0x01f9d1, 0x01f9dd)); + SET_ENCODINGS.put("EBase", CodePointSet.createNoDedup(0x00261d, 0x00261d, 0x0026f9, 0x0026f9, 0x00270a, 0x00270d, 0x01f385, 0x01f385, 0x01f3c2, 0x01f3c4, 0x01f3c7, 0x01f3c7, 0x01f3ca, + 0x01f3cc, 0x01f442, 0x01f443, 0x01f446, 0x01f450, 0x01f466, 0x01f478, 0x01f47c, 0x01f47c, 0x01f481, 0x01f483, 0x01f485, 0x01f487, 0x01f48f, 0x01f48f, 0x01f491, 0x01f491, + 0x01f4aa, 0x01f4aa, 0x01f574, 0x01f575, 0x01f57a, 0x01f57a, 0x01f590, 0x01f590, 0x01f595, 0x01f596, 0x01f645, 0x01f647, 0x01f64b, 0x01f64f, 0x01f6a3, 0x01f6a3, 0x01f6b4, + 0x01f6b6, 0x01f6c0, 0x01f6c0, 0x01f6cc, 0x01f6cc, 0x01f90c, 0x01f90c, 0x01f90f, 0x01f90f, 0x01f918, 0x01f91f, 0x01f926, 0x01f926, 0x01f930, 0x01f939, 0x01f93c, 0x01f93e, + 0x01f977, 0x01f977, 0x01f9b5, 0x01f9b6, 0x01f9b8, 0x01f9b9, 0x01f9bb, 0x01f9bb, 0x01f9cd, 0x01f9cf, 0x01f9d1, 0x01f9dd, 0x01fac3, 0x01fac5, 0x01faf0, 0x01faf6)); } private static void populateECOMP() { @@ -1728,8 +1762,8 @@ private static void populateEPRES() { 0x01f22f, 0x01f232, 0x01f236, 0x01f238, 0x01f23a, 0x01f250, 0x01f251, 0x01f300, 0x01f320, 0x01f32d, 0x01f335, 0x01f337, 0x01f37c, 0x01f37e, 0x01f393, 0x01f3a0, 0x01f3ca, 0x01f3cf, 0x01f3d3, 0x01f3e0, 0x01f3f0, 0x01f3f4, 0x01f3f4, 0x01f3f8, 0x01f43e, 0x01f440, 0x01f440, 0x01f442, 0x01f4fc, 0x01f4ff, 0x01f53d, 0x01f54b, 0x01f54e, 0x01f550, 0x01f567, 0x01f57a, 0x01f57a, 0x01f595, 0x01f596, 0x01f5a4, 0x01f5a4, 0x01f5fb, 0x01f64f, 0x01f680, 0x01f6c5, 0x01f6cc, 0x01f6cc, 0x01f6d0, 0x01f6d2, 0x01f6d5, 0x01f6d7, - 0x01f6eb, 0x01f6ec, 0x01f6f4, 0x01f6fc, 0x01f7e0, 0x01f7eb, 0x01f90c, 0x01f93a, 0x01f93c, 0x01f945, 0x01f947, 0x01f978, 0x01f97a, 0x01f9cb, 0x01f9cd, 0x01f9ff, 0x01fa70, - 0x01fa74, 0x01fa78, 0x01fa7a, 0x01fa80, 0x01fa86, 0x01fa90, 0x01faa8, 0x01fab0, 0x01fab6, 0x01fac0, 0x01fac2, 0x01fad0, 0x01fad6)); + 0x01f6dd, 0x01f6df, 0x01f6eb, 0x01f6ec, 0x01f6f4, 0x01f6fc, 0x01f7e0, 0x01f7eb, 0x01f7f0, 0x01f7f0, 0x01f90c, 0x01f93a, 0x01f93c, 0x01f945, 0x01f947, 0x01f9ff, 0x01fa70, + 0x01fa74, 0x01fa78, 0x01fa7c, 0x01fa80, 0x01fa86, 0x01fa90, 0x01faac, 0x01fab0, 0x01faba, 0x01fac0, 0x01fac5, 0x01fad0, 0x01fad9, 0x01fae0, 0x01fae7, 0x01faf0, 0x01faf6)); } private static void populateEMOJI() { @@ -1749,16 +1783,18 @@ private static void populateEMOJI() { 0x01f4fd, 0x01f4ff, 0x01f53d, 0x01f549, 0x01f54e, 0x01f550, 0x01f567, 0x01f56f, 0x01f570, 0x01f573, 0x01f57a, 0x01f587, 0x01f587, 0x01f58a, 0x01f58d, 0x01f590, 0x01f590, 0x01f595, 0x01f596, 0x01f5a4, 0x01f5a5, 0x01f5a8, 0x01f5a8, 0x01f5b1, 0x01f5b2, 0x01f5bc, 0x01f5bc, 0x01f5c2, 0x01f5c4, 0x01f5d1, 0x01f5d3, 0x01f5dc, 0x01f5de, 0x01f5e1, 0x01f5e1, 0x01f5e3, 0x01f5e3, 0x01f5e8, 0x01f5e8, 0x01f5ef, 0x01f5ef, 0x01f5f3, 0x01f5f3, 0x01f5fa, 0x01f64f, 0x01f680, 0x01f6c5, 0x01f6cb, 0x01f6d2, 0x01f6d5, 0x01f6d7, - 0x01f6e0, 0x01f6e5, 0x01f6e9, 0x01f6e9, 0x01f6eb, 0x01f6ec, 0x01f6f0, 0x01f6f0, 0x01f6f3, 0x01f6fc, 0x01f7e0, 0x01f7eb, 0x01f90c, 0x01f93a, 0x01f93c, 0x01f945, 0x01f947, - 0x01f978, 0x01f97a, 0x01f9cb, 0x01f9cd, 0x01f9ff, 0x01fa70, 0x01fa74, 0x01fa78, 0x01fa7a, 0x01fa80, 0x01fa86, 0x01fa90, 0x01faa8, 0x01fab0, 0x01fab6, 0x01fac0, 0x01fac2, - 0x01fad0, 0x01fad6)); + 0x01f6dd, 0x01f6e5, 0x01f6e9, 0x01f6e9, 0x01f6eb, 0x01f6ec, 0x01f6f0, 0x01f6f0, 0x01f6f3, 0x01f6fc, 0x01f7e0, 0x01f7eb, 0x01f7f0, 0x01f7f0, 0x01f90c, 0x01f93a, 0x01f93c, + 0x01f945, 0x01f947, 0x01f9ff, 0x01fa70, 0x01fa74, 0x01fa78, 0x01fa7c, 0x01fa80, 0x01fa86, 0x01fa90, 0x01faac, 0x01fab0, 0x01faba, 0x01fac0, 0x01fac5, 0x01fad0, 0x01fad9, + 0x01fae0, 0x01fae7, 0x01faf0, 0x01faf6)); } private static void populateEXT() { - SET_ENCODINGS.put("Ext", CodePointSet.createNoDedup(0x0000b7, 0x0000b7, 0x0002d0, 0x0002d1, 0x000640, 0x000640, 0x0007fa, 0x0007fa, 0x000b55, 0x000b55, 0x000e46, 0x000e46, 0x000ec6, 0x000ec6, - 0x00180a, 0x00180a, 0x001843, 0x001843, 0x001aa7, 0x001aa7, 0x001c36, 0x001c36, 0x001c7b, 0x001c7b, 0x003005, 0x003005, 0x003031, 0x003035, 0x00309d, 0x00309e, 0x0030fc, - 0x0030fe, 0x00a015, 0x00a015, 0x00a60c, 0x00a60c, 0x00a9cf, 0x00a9cf, 0x00a9e6, 0x00a9e6, 0x00aa70, 0x00aa70, 0x00aadd, 0x00aadd, 0x00aaf3, 0x00aaf4, 0x00ff70, 0x00ff70, - 0x01135d, 0x01135d, 0x0115c6, 0x0115c8, 0x011a98, 0x011a98, 0x016b42, 0x016b43, 0x016fe0, 0x016fe1, 0x016fe3, 0x016fe3, 0x01e13c, 0x01e13d, 0x01e944, 0x01e946)); + SET_ENCODINGS.put("Ext", + CodePointSet.createNoDedup(0x0000b7, 0x0000b7, 0x0002d0, 0x0002d1, 0x000640, 0x000640, 0x0007fa, 0x0007fa, 0x000b55, 0x000b55, 0x000e46, 0x000e46, 0x000ec6, 0x000ec6, 0x00180a, + 0x00180a, 0x001843, 0x001843, 0x001aa7, 0x001aa7, 0x001c36, 0x001c36, 0x001c7b, 0x001c7b, 0x003005, 0x003005, 0x003031, 0x003035, 0x00309d, 0x00309e, 0x0030fc, + 0x0030fe, 0x00a015, 0x00a015, 0x00a60c, 0x00a60c, 0x00a9cf, 0x00a9cf, 0x00a9e6, 0x00a9e6, 0x00aa70, 0x00aa70, 0x00aadd, 0x00aadd, 0x00aaf3, 0x00aaf4, 0x00ff70, + 0x00ff70, 0x010781, 0x010782, 0x01135d, 0x01135d, 0x0115c6, 0x0115c8, 0x011a98, 0x011a98, 0x016b42, 0x016b43, 0x016fe0, 0x016fe1, 0x016fe3, 0x016fe3, 0x01e13c, + 0x01e13d, 0x01e944, 0x01e946)); } private static void populateEXTPICT() { @@ -1778,10 +1814,10 @@ private static void populateEXTPICT() { private static void populateGR_BASE() { SET_ENCODINGS.put("Gr_Base", CodePointSet.createNoDedup(0x000020, 0x00007e, 0x0000a0, 0x0000ac, 0x0000ae, 0x0002ff, 0x000370, 0x000377, 0x00037a, 0x00037f, 0x000384, 0x00038a, 0x00038c, 0x00038c, 0x00038e, 0x0003a1, 0x0003a3, 0x000482, 0x00048a, 0x00052f, 0x000531, 0x000556, 0x000559, 0x00058a, 0x00058d, 0x00058f, 0x0005be, 0x0005be, 0x0005c0, 0x0005c0, - 0x0005c3, 0x0005c3, 0x0005c6, 0x0005c6, 0x0005d0, 0x0005ea, 0x0005ef, 0x0005f4, 0x000606, 0x00060f, 0x00061b, 0x00061b, 0x00061e, 0x00064a, 0x000660, 0x00066f, 0x000671, + 0x0005c3, 0x0005c3, 0x0005c6, 0x0005c6, 0x0005d0, 0x0005ea, 0x0005ef, 0x0005f4, 0x000606, 0x00060f, 0x00061b, 0x00061b, 0x00061d, 0x00064a, 0x000660, 0x00066f, 0x000671, 0x0006d5, 0x0006de, 0x0006de, 0x0006e5, 0x0006e6, 0x0006e9, 0x0006e9, 0x0006ee, 0x00070d, 0x000710, 0x000710, 0x000712, 0x00072f, 0x00074d, 0x0007a5, 0x0007b1, 0x0007b1, 0x0007c0, 0x0007ea, 0x0007f4, 0x0007fa, 0x0007fe, 0x000815, 0x00081a, 0x00081a, 0x000824, 0x000824, 0x000828, 0x000828, 0x000830, 0x00083e, 0x000840, 0x000858, 0x00085e, - 0x00085e, 0x000860, 0x00086a, 0x0008a0, 0x0008b4, 0x0008b6, 0x0008c7, 0x000903, 0x000939, 0x00093b, 0x00093b, 0x00093d, 0x000940, 0x000949, 0x00094c, 0x00094e, 0x000950, + 0x00085e, 0x000860, 0x00086a, 0x000870, 0x00088e, 0x0008a0, 0x0008c9, 0x000903, 0x000939, 0x00093b, 0x00093b, 0x00093d, 0x000940, 0x000949, 0x00094c, 0x00094e, 0x000950, 0x000958, 0x000961, 0x000964, 0x000980, 0x000982, 0x000983, 0x000985, 0x00098c, 0x00098f, 0x000990, 0x000993, 0x0009a8, 0x0009aa, 0x0009b0, 0x0009b2, 0x0009b2, 0x0009b6, 0x0009b9, 0x0009bd, 0x0009bd, 0x0009bf, 0x0009c0, 0x0009c7, 0x0009c8, 0x0009cb, 0x0009cc, 0x0009ce, 0x0009ce, 0x0009dc, 0x0009dd, 0x0009df, 0x0009e1, 0x0009e6, 0x0009fd, 0x000a03, 0x000a03, 0x000a05, 0x000a0a, 0x000a0f, 0x000a10, 0x000a13, 0x000a28, 0x000a2a, 0x000a30, 0x000a32, 0x000a33, 0x000a35, 0x000a36, 0x000a38, 0x000a39, 0x000a3e, @@ -1791,134 +1827,138 @@ private static void populateGR_BASE() { 0x000b35, 0x000b39, 0x000b3d, 0x000b3d, 0x000b40, 0x000b40, 0x000b47, 0x000b48, 0x000b4b, 0x000b4c, 0x000b5c, 0x000b5d, 0x000b5f, 0x000b61, 0x000b66, 0x000b77, 0x000b83, 0x000b83, 0x000b85, 0x000b8a, 0x000b8e, 0x000b90, 0x000b92, 0x000b95, 0x000b99, 0x000b9a, 0x000b9c, 0x000b9c, 0x000b9e, 0x000b9f, 0x000ba3, 0x000ba4, 0x000ba8, 0x000baa, 0x000bae, 0x000bb9, 0x000bbf, 0x000bbf, 0x000bc1, 0x000bc2, 0x000bc6, 0x000bc8, 0x000bca, 0x000bcc, 0x000bd0, 0x000bd0, 0x000be6, 0x000bfa, 0x000c01, 0x000c03, 0x000c05, - 0x000c0c, 0x000c0e, 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3d, 0x000c3d, 0x000c41, 0x000c44, 0x000c58, 0x000c5a, 0x000c60, 0x000c61, 0x000c66, 0x000c6f, - 0x000c77, 0x000c80, 0x000c82, 0x000c8c, 0x000c8e, 0x000c90, 0x000c92, 0x000ca8, 0x000caa, 0x000cb3, 0x000cb5, 0x000cb9, 0x000cbd, 0x000cbe, 0x000cc0, 0x000cc1, 0x000cc3, - 0x000cc4, 0x000cc7, 0x000cc8, 0x000cca, 0x000ccb, 0x000cde, 0x000cde, 0x000ce0, 0x000ce1, 0x000ce6, 0x000cef, 0x000cf1, 0x000cf2, 0x000d02, 0x000d0c, 0x000d0e, 0x000d10, - 0x000d12, 0x000d3a, 0x000d3d, 0x000d3d, 0x000d3f, 0x000d40, 0x000d46, 0x000d48, 0x000d4a, 0x000d4c, 0x000d4e, 0x000d4f, 0x000d54, 0x000d56, 0x000d58, 0x000d61, 0x000d66, - 0x000d7f, 0x000d82, 0x000d83, 0x000d85, 0x000d96, 0x000d9a, 0x000db1, 0x000db3, 0x000dbb, 0x000dbd, 0x000dbd, 0x000dc0, 0x000dc6, 0x000dd0, 0x000dd1, 0x000dd8, 0x000dde, - 0x000de6, 0x000def, 0x000df2, 0x000df4, 0x000e01, 0x000e30, 0x000e32, 0x000e33, 0x000e3f, 0x000e46, 0x000e4f, 0x000e5b, 0x000e81, 0x000e82, 0x000e84, 0x000e84, 0x000e86, - 0x000e8a, 0x000e8c, 0x000ea3, 0x000ea5, 0x000ea5, 0x000ea7, 0x000eb0, 0x000eb2, 0x000eb3, 0x000ebd, 0x000ebd, 0x000ec0, 0x000ec4, 0x000ec6, 0x000ec6, 0x000ed0, 0x000ed9, - 0x000edc, 0x000edf, 0x000f00, 0x000f17, 0x000f1a, 0x000f34, 0x000f36, 0x000f36, 0x000f38, 0x000f38, 0x000f3a, 0x000f47, 0x000f49, 0x000f6c, 0x000f7f, 0x000f7f, 0x000f85, - 0x000f85, 0x000f88, 0x000f8c, 0x000fbe, 0x000fc5, 0x000fc7, 0x000fcc, 0x000fce, 0x000fda, 0x001000, 0x00102c, 0x001031, 0x001031, 0x001038, 0x001038, 0x00103b, 0x00103c, - 0x00103f, 0x001057, 0x00105a, 0x00105d, 0x001061, 0x001070, 0x001075, 0x001081, 0x001083, 0x001084, 0x001087, 0x00108c, 0x00108e, 0x00109c, 0x00109e, 0x0010c5, 0x0010c7, - 0x0010c7, 0x0010cd, 0x0010cd, 0x0010d0, 0x001248, 0x00124a, 0x00124d, 0x001250, 0x001256, 0x001258, 0x001258, 0x00125a, 0x00125d, 0x001260, 0x001288, 0x00128a, 0x00128d, - 0x001290, 0x0012b0, 0x0012b2, 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, 0x0012d8, 0x001310, 0x001312, 0x001315, 0x001318, - 0x00135a, 0x001360, 0x00137c, 0x001380, 0x001399, 0x0013a0, 0x0013f5, 0x0013f8, 0x0013fd, 0x001400, 0x00169c, 0x0016a0, 0x0016f8, 0x001700, 0x00170c, 0x00170e, 0x001711, - 0x001720, 0x001731, 0x001735, 0x001736, 0x001740, 0x001751, 0x001760, 0x00176c, 0x00176e, 0x001770, 0x001780, 0x0017b3, 0x0017b6, 0x0017b6, 0x0017be, 0x0017c5, 0x0017c7, - 0x0017c8, 0x0017d4, 0x0017dc, 0x0017e0, 0x0017e9, 0x0017f0, 0x0017f9, 0x001800, 0x00180a, 0x001810, 0x001819, 0x001820, 0x001878, 0x001880, 0x001884, 0x001887, 0x0018a8, - 0x0018aa, 0x0018aa, 0x0018b0, 0x0018f5, 0x001900, 0x00191e, 0x001923, 0x001926, 0x001929, 0x00192b, 0x001930, 0x001931, 0x001933, 0x001938, 0x001940, 0x001940, 0x001944, - 0x00196d, 0x001970, 0x001974, 0x001980, 0x0019ab, 0x0019b0, 0x0019c9, 0x0019d0, 0x0019da, 0x0019de, 0x001a16, 0x001a19, 0x001a1a, 0x001a1e, 0x001a55, 0x001a57, 0x001a57, - 0x001a61, 0x001a61, 0x001a63, 0x001a64, 0x001a6d, 0x001a72, 0x001a80, 0x001a89, 0x001a90, 0x001a99, 0x001aa0, 0x001aad, 0x001b04, 0x001b33, 0x001b3b, 0x001b3b, 0x001b3d, - 0x001b41, 0x001b43, 0x001b4b, 0x001b50, 0x001b6a, 0x001b74, 0x001b7c, 0x001b82, 0x001ba1, 0x001ba6, 0x001ba7, 0x001baa, 0x001baa, 0x001bae, 0x001be5, 0x001be7, 0x001be7, - 0x001bea, 0x001bec, 0x001bee, 0x001bee, 0x001bf2, 0x001bf3, 0x001bfc, 0x001c2b, 0x001c34, 0x001c35, 0x001c3b, 0x001c49, 0x001c4d, 0x001c88, 0x001c90, 0x001cba, 0x001cbd, - 0x001cc7, 0x001cd3, 0x001cd3, 0x001ce1, 0x001ce1, 0x001ce9, 0x001cec, 0x001cee, 0x001cf3, 0x001cf5, 0x001cf7, 0x001cfa, 0x001cfa, 0x001d00, 0x001dbf, 0x001e00, 0x001f15, - 0x001f18, 0x001f1d, 0x001f20, 0x001f45, 0x001f48, 0x001f4d, 0x001f50, 0x001f57, 0x001f59, 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f7d, 0x001f80, - 0x001fb4, 0x001fb6, 0x001fc4, 0x001fc6, 0x001fd3, 0x001fd6, 0x001fdb, 0x001fdd, 0x001fef, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ffe, 0x002000, 0x00200a, 0x002010, 0x002027, - 0x00202f, 0x00205f, 0x002070, 0x002071, 0x002074, 0x00208e, 0x002090, 0x00209c, 0x0020a0, 0x0020bf, 0x002100, 0x00218b, 0x002190, 0x002426, 0x002440, 0x00244a, 0x002460, - 0x002b73, 0x002b76, 0x002b95, 0x002b97, 0x002c2e, 0x002c30, 0x002c5e, 0x002c60, 0x002cee, 0x002cf2, 0x002cf3, 0x002cf9, 0x002d25, 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, - 0x002d30, 0x002d67, 0x002d6f, 0x002d70, 0x002d80, 0x002d96, 0x002da0, 0x002da6, 0x002da8, 0x002dae, 0x002db0, 0x002db6, 0x002db8, 0x002dbe, 0x002dc0, 0x002dc6, 0x002dc8, - 0x002dce, 0x002dd0, 0x002dd6, 0x002dd8, 0x002dde, 0x002e00, 0x002e52, 0x002e80, 0x002e99, 0x002e9b, 0x002ef3, 0x002f00, 0x002fd5, 0x002ff0, 0x002ffb, 0x003000, 0x003029, - 0x003030, 0x00303f, 0x003041, 0x003096, 0x00309b, 0x0030ff, 0x003105, 0x00312f, 0x003131, 0x00318e, 0x003190, 0x0031e3, 0x0031f0, 0x00321e, 0x003220, 0x009ffc, 0x00a000, - 0x00a48c, 0x00a490, 0x00a4c6, 0x00a4d0, 0x00a62b, 0x00a640, 0x00a66e, 0x00a673, 0x00a673, 0x00a67e, 0x00a69d, 0x00a6a0, 0x00a6ef, 0x00a6f2, 0x00a6f7, 0x00a700, 0x00a7bf, - 0x00a7c2, 0x00a7ca, 0x00a7f5, 0x00a801, 0x00a803, 0x00a805, 0x00a807, 0x00a80a, 0x00a80c, 0x00a824, 0x00a827, 0x00a82b, 0x00a830, 0x00a839, 0x00a840, 0x00a877, 0x00a880, + 0x000c0c, 0x000c0e, 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3d, 0x000c3d, 0x000c41, 0x000c44, 0x000c58, 0x000c5a, 0x000c5d, 0x000c5d, 0x000c60, 0x000c61, + 0x000c66, 0x000c6f, 0x000c77, 0x000c80, 0x000c82, 0x000c8c, 0x000c8e, 0x000c90, 0x000c92, 0x000ca8, 0x000caa, 0x000cb3, 0x000cb5, 0x000cb9, 0x000cbd, 0x000cbe, 0x000cc0, + 0x000cc1, 0x000cc3, 0x000cc4, 0x000cc7, 0x000cc8, 0x000cca, 0x000ccb, 0x000cdd, 0x000cde, 0x000ce0, 0x000ce1, 0x000ce6, 0x000cef, 0x000cf1, 0x000cf2, 0x000d02, 0x000d0c, + 0x000d0e, 0x000d10, 0x000d12, 0x000d3a, 0x000d3d, 0x000d3d, 0x000d3f, 0x000d40, 0x000d46, 0x000d48, 0x000d4a, 0x000d4c, 0x000d4e, 0x000d4f, 0x000d54, 0x000d56, 0x000d58, + 0x000d61, 0x000d66, 0x000d7f, 0x000d82, 0x000d83, 0x000d85, 0x000d96, 0x000d9a, 0x000db1, 0x000db3, 0x000dbb, 0x000dbd, 0x000dbd, 0x000dc0, 0x000dc6, 0x000dd0, 0x000dd1, + 0x000dd8, 0x000dde, 0x000de6, 0x000def, 0x000df2, 0x000df4, 0x000e01, 0x000e30, 0x000e32, 0x000e33, 0x000e3f, 0x000e46, 0x000e4f, 0x000e5b, 0x000e81, 0x000e82, 0x000e84, + 0x000e84, 0x000e86, 0x000e8a, 0x000e8c, 0x000ea3, 0x000ea5, 0x000ea5, 0x000ea7, 0x000eb0, 0x000eb2, 0x000eb3, 0x000ebd, 0x000ebd, 0x000ec0, 0x000ec4, 0x000ec6, 0x000ec6, + 0x000ed0, 0x000ed9, 0x000edc, 0x000edf, 0x000f00, 0x000f17, 0x000f1a, 0x000f34, 0x000f36, 0x000f36, 0x000f38, 0x000f38, 0x000f3a, 0x000f47, 0x000f49, 0x000f6c, 0x000f7f, + 0x000f7f, 0x000f85, 0x000f85, 0x000f88, 0x000f8c, 0x000fbe, 0x000fc5, 0x000fc7, 0x000fcc, 0x000fce, 0x000fda, 0x001000, 0x00102c, 0x001031, 0x001031, 0x001038, 0x001038, + 0x00103b, 0x00103c, 0x00103f, 0x001057, 0x00105a, 0x00105d, 0x001061, 0x001070, 0x001075, 0x001081, 0x001083, 0x001084, 0x001087, 0x00108c, 0x00108e, 0x00109c, 0x00109e, + 0x0010c5, 0x0010c7, 0x0010c7, 0x0010cd, 0x0010cd, 0x0010d0, 0x001248, 0x00124a, 0x00124d, 0x001250, 0x001256, 0x001258, 0x001258, 0x00125a, 0x00125d, 0x001260, 0x001288, + 0x00128a, 0x00128d, 0x001290, 0x0012b0, 0x0012b2, 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, 0x0012d8, 0x001310, 0x001312, + 0x001315, 0x001318, 0x00135a, 0x001360, 0x00137c, 0x001380, 0x001399, 0x0013a0, 0x0013f5, 0x0013f8, 0x0013fd, 0x001400, 0x00169c, 0x0016a0, 0x0016f8, 0x001700, 0x001711, + 0x001715, 0x001715, 0x00171f, 0x001731, 0x001734, 0x001736, 0x001740, 0x001751, 0x001760, 0x00176c, 0x00176e, 0x001770, 0x001780, 0x0017b3, 0x0017b6, 0x0017b6, 0x0017be, + 0x0017c5, 0x0017c7, 0x0017c8, 0x0017d4, 0x0017dc, 0x0017e0, 0x0017e9, 0x0017f0, 0x0017f9, 0x001800, 0x00180a, 0x001810, 0x001819, 0x001820, 0x001878, 0x001880, 0x001884, + 0x001887, 0x0018a8, 0x0018aa, 0x0018aa, 0x0018b0, 0x0018f5, 0x001900, 0x00191e, 0x001923, 0x001926, 0x001929, 0x00192b, 0x001930, 0x001931, 0x001933, 0x001938, 0x001940, + 0x001940, 0x001944, 0x00196d, 0x001970, 0x001974, 0x001980, 0x0019ab, 0x0019b0, 0x0019c9, 0x0019d0, 0x0019da, 0x0019de, 0x001a16, 0x001a19, 0x001a1a, 0x001a1e, 0x001a55, + 0x001a57, 0x001a57, 0x001a61, 0x001a61, 0x001a63, 0x001a64, 0x001a6d, 0x001a72, 0x001a80, 0x001a89, 0x001a90, 0x001a99, 0x001aa0, 0x001aad, 0x001b04, 0x001b33, 0x001b3b, + 0x001b3b, 0x001b3d, 0x001b41, 0x001b43, 0x001b4c, 0x001b50, 0x001b6a, 0x001b74, 0x001b7e, 0x001b82, 0x001ba1, 0x001ba6, 0x001ba7, 0x001baa, 0x001baa, 0x001bae, 0x001be5, + 0x001be7, 0x001be7, 0x001bea, 0x001bec, 0x001bee, 0x001bee, 0x001bf2, 0x001bf3, 0x001bfc, 0x001c2b, 0x001c34, 0x001c35, 0x001c3b, 0x001c49, 0x001c4d, 0x001c88, 0x001c90, + 0x001cba, 0x001cbd, 0x001cc7, 0x001cd3, 0x001cd3, 0x001ce1, 0x001ce1, 0x001ce9, 0x001cec, 0x001cee, 0x001cf3, 0x001cf5, 0x001cf7, 0x001cfa, 0x001cfa, 0x001d00, 0x001dbf, + 0x001e00, 0x001f15, 0x001f18, 0x001f1d, 0x001f20, 0x001f45, 0x001f48, 0x001f4d, 0x001f50, 0x001f57, 0x001f59, 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, + 0x001f7d, 0x001f80, 0x001fb4, 0x001fb6, 0x001fc4, 0x001fc6, 0x001fd3, 0x001fd6, 0x001fdb, 0x001fdd, 0x001fef, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ffe, 0x002000, 0x00200a, + 0x002010, 0x002027, 0x00202f, 0x00205f, 0x002070, 0x002071, 0x002074, 0x00208e, 0x002090, 0x00209c, 0x0020a0, 0x0020c0, 0x002100, 0x00218b, 0x002190, 0x002426, 0x002440, + 0x00244a, 0x002460, 0x002b73, 0x002b76, 0x002b95, 0x002b97, 0x002cee, 0x002cf2, 0x002cf3, 0x002cf9, 0x002d25, 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, 0x002d30, 0x002d67, + 0x002d6f, 0x002d70, 0x002d80, 0x002d96, 0x002da0, 0x002da6, 0x002da8, 0x002dae, 0x002db0, 0x002db6, 0x002db8, 0x002dbe, 0x002dc0, 0x002dc6, 0x002dc8, 0x002dce, 0x002dd0, + 0x002dd6, 0x002dd8, 0x002dde, 0x002e00, 0x002e5d, 0x002e80, 0x002e99, 0x002e9b, 0x002ef3, 0x002f00, 0x002fd5, 0x002ff0, 0x002ffb, 0x003000, 0x003029, 0x003030, 0x00303f, + 0x003041, 0x003096, 0x00309b, 0x0030ff, 0x003105, 0x00312f, 0x003131, 0x00318e, 0x003190, 0x0031e3, 0x0031f0, 0x00321e, 0x003220, 0x00a48c, 0x00a490, 0x00a4c6, 0x00a4d0, + 0x00a62b, 0x00a640, 0x00a66e, 0x00a673, 0x00a673, 0x00a67e, 0x00a69d, 0x00a6a0, 0x00a6ef, 0x00a6f2, 0x00a6f7, 0x00a700, 0x00a7ca, 0x00a7d0, 0x00a7d1, 0x00a7d3, 0x00a7d3, + 0x00a7d5, 0x00a7d9, 0x00a7f2, 0x00a801, 0x00a803, 0x00a805, 0x00a807, 0x00a80a, 0x00a80c, 0x00a824, 0x00a827, 0x00a82b, 0x00a830, 0x00a839, 0x00a840, 0x00a877, 0x00a880, 0x00a8c3, 0x00a8ce, 0x00a8d9, 0x00a8f2, 0x00a8fe, 0x00a900, 0x00a925, 0x00a92e, 0x00a946, 0x00a952, 0x00a953, 0x00a95f, 0x00a97c, 0x00a983, 0x00a9b2, 0x00a9b4, 0x00a9b5, 0x00a9ba, 0x00a9bb, 0x00a9be, 0x00a9cd, 0x00a9cf, 0x00a9d9, 0x00a9de, 0x00a9e4, 0x00a9e6, 0x00a9fe, 0x00aa00, 0x00aa28, 0x00aa2f, 0x00aa30, 0x00aa33, 0x00aa34, 0x00aa40, 0x00aa42, 0x00aa44, 0x00aa4b, 0x00aa4d, 0x00aa4d, 0x00aa50, 0x00aa59, 0x00aa5c, 0x00aa7b, 0x00aa7d, 0x00aaaf, 0x00aab1, 0x00aab1, 0x00aab5, 0x00aab6, 0x00aab9, 0x00aabd, 0x00aac0, 0x00aac0, 0x00aac2, 0x00aac2, 0x00aadb, 0x00aaeb, 0x00aaee, 0x00aaf5, 0x00ab01, 0x00ab06, 0x00ab09, 0x00ab0e, 0x00ab11, 0x00ab16, 0x00ab20, 0x00ab26, 0x00ab28, 0x00ab2e, 0x00ab30, 0x00ab6b, 0x00ab70, 0x00abe4, 0x00abe6, 0x00abe7, 0x00abe9, 0x00abec, 0x00abf0, 0x00abf9, 0x00ac00, 0x00d7a3, 0x00d7b0, 0x00d7c6, 0x00d7cb, 0x00d7fb, 0x00f900, 0x00fa6d, 0x00fa70, 0x00fad9, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, 0x00fb1d, 0x00fb1d, 0x00fb1f, 0x00fb36, 0x00fb38, 0x00fb3c, 0x00fb3e, 0x00fb3e, 0x00fb40, - 0x00fb41, 0x00fb43, 0x00fb44, 0x00fb46, 0x00fbc1, 0x00fbd3, 0x00fd3f, 0x00fd50, 0x00fd8f, 0x00fd92, 0x00fdc7, 0x00fdf0, 0x00fdfd, 0x00fe10, 0x00fe19, 0x00fe30, 0x00fe52, + 0x00fb41, 0x00fb43, 0x00fb44, 0x00fb46, 0x00fbc2, 0x00fbd3, 0x00fd8f, 0x00fd92, 0x00fdc7, 0x00fdcf, 0x00fdcf, 0x00fdf0, 0x00fdff, 0x00fe10, 0x00fe19, 0x00fe30, 0x00fe52, 0x00fe54, 0x00fe66, 0x00fe68, 0x00fe6b, 0x00fe70, 0x00fe74, 0x00fe76, 0x00fefc, 0x00ff01, 0x00ff9d, 0x00ffa0, 0x00ffbe, 0x00ffc2, 0x00ffc7, 0x00ffca, 0x00ffcf, 0x00ffd2, 0x00ffd7, 0x00ffda, 0x00ffdc, 0x00ffe0, 0x00ffe6, 0x00ffe8, 0x00ffee, 0x00fffc, 0x00fffd, 0x010000, 0x01000b, 0x01000d, 0x010026, 0x010028, 0x01003a, 0x01003c, 0x01003d, 0x01003f, 0x01004d, 0x010050, 0x01005d, 0x010080, 0x0100fa, 0x010100, 0x010102, 0x010107, 0x010133, 0x010137, 0x01018e, 0x010190, 0x01019c, 0x0101a0, 0x0101a0, 0x0101d0, 0x0101fc, 0x010280, 0x01029c, 0x0102a0, 0x0102d0, 0x0102e1, 0x0102fb, 0x010300, 0x010323, 0x01032d, 0x01034a, 0x010350, 0x010375, 0x010380, 0x01039d, 0x01039f, 0x0103c3, - 0x0103c8, 0x0103d5, 0x010400, 0x01049d, 0x0104a0, 0x0104a9, 0x0104b0, 0x0104d3, 0x0104d8, 0x0104fb, 0x010500, 0x010527, 0x010530, 0x010563, 0x01056f, 0x01056f, 0x010600, - 0x010736, 0x010740, 0x010755, 0x010760, 0x010767, 0x010800, 0x010805, 0x010808, 0x010808, 0x01080a, 0x010835, 0x010837, 0x010838, 0x01083c, 0x01083c, 0x01083f, 0x010855, - 0x010857, 0x01089e, 0x0108a7, 0x0108af, 0x0108e0, 0x0108f2, 0x0108f4, 0x0108f5, 0x0108fb, 0x01091b, 0x01091f, 0x010939, 0x01093f, 0x01093f, 0x010980, 0x0109b7, 0x0109bc, - 0x0109cf, 0x0109d2, 0x010a00, 0x010a10, 0x010a13, 0x010a15, 0x010a17, 0x010a19, 0x010a35, 0x010a40, 0x010a48, 0x010a50, 0x010a58, 0x010a60, 0x010a9f, 0x010ac0, 0x010ae4, - 0x010aeb, 0x010af6, 0x010b00, 0x010b35, 0x010b39, 0x010b55, 0x010b58, 0x010b72, 0x010b78, 0x010b91, 0x010b99, 0x010b9c, 0x010ba9, 0x010baf, 0x010c00, 0x010c48, 0x010c80, - 0x010cb2, 0x010cc0, 0x010cf2, 0x010cfa, 0x010d23, 0x010d30, 0x010d39, 0x010e60, 0x010e7e, 0x010e80, 0x010ea9, 0x010ead, 0x010ead, 0x010eb0, 0x010eb1, 0x010f00, 0x010f27, - 0x010f30, 0x010f45, 0x010f51, 0x010f59, 0x010fb0, 0x010fcb, 0x010fe0, 0x010ff6, 0x011000, 0x011000, 0x011002, 0x011037, 0x011047, 0x01104d, 0x011052, 0x01106f, 0x011082, - 0x0110b2, 0x0110b7, 0x0110b8, 0x0110bb, 0x0110bc, 0x0110be, 0x0110c1, 0x0110d0, 0x0110e8, 0x0110f0, 0x0110f9, 0x011103, 0x011126, 0x01112c, 0x01112c, 0x011136, 0x011147, - 0x011150, 0x011172, 0x011174, 0x011176, 0x011182, 0x0111b5, 0x0111bf, 0x0111c8, 0x0111cd, 0x0111ce, 0x0111d0, 0x0111df, 0x0111e1, 0x0111f4, 0x011200, 0x011211, 0x011213, - 0x01122e, 0x011232, 0x011233, 0x011235, 0x011235, 0x011238, 0x01123d, 0x011280, 0x011286, 0x011288, 0x011288, 0x01128a, 0x01128d, 0x01128f, 0x01129d, 0x01129f, 0x0112a9, - 0x0112b0, 0x0112de, 0x0112e0, 0x0112e2, 0x0112f0, 0x0112f9, 0x011302, 0x011303, 0x011305, 0x01130c, 0x01130f, 0x011310, 0x011313, 0x011328, 0x01132a, 0x011330, 0x011332, - 0x011333, 0x011335, 0x011339, 0x01133d, 0x01133d, 0x01133f, 0x01133f, 0x011341, 0x011344, 0x011347, 0x011348, 0x01134b, 0x01134d, 0x011350, 0x011350, 0x01135d, 0x011363, - 0x011400, 0x011437, 0x011440, 0x011441, 0x011445, 0x011445, 0x011447, 0x01145b, 0x01145d, 0x01145d, 0x01145f, 0x011461, 0x011480, 0x0114af, 0x0114b1, 0x0114b2, 0x0114b9, - 0x0114b9, 0x0114bb, 0x0114bc, 0x0114be, 0x0114be, 0x0114c1, 0x0114c1, 0x0114c4, 0x0114c7, 0x0114d0, 0x0114d9, 0x011580, 0x0115ae, 0x0115b0, 0x0115b1, 0x0115b8, 0x0115bb, - 0x0115be, 0x0115be, 0x0115c1, 0x0115db, 0x011600, 0x011632, 0x01163b, 0x01163c, 0x01163e, 0x01163e, 0x011641, 0x011644, 0x011650, 0x011659, 0x011660, 0x01166c, 0x011680, - 0x0116aa, 0x0116ac, 0x0116ac, 0x0116ae, 0x0116af, 0x0116b6, 0x0116b6, 0x0116b8, 0x0116b8, 0x0116c0, 0x0116c9, 0x011700, 0x01171a, 0x011720, 0x011721, 0x011726, 0x011726, - 0x011730, 0x01173f, 0x011800, 0x01182e, 0x011838, 0x011838, 0x01183b, 0x01183b, 0x0118a0, 0x0118f2, 0x0118ff, 0x011906, 0x011909, 0x011909, 0x01190c, 0x011913, 0x011915, - 0x011916, 0x011918, 0x01192f, 0x011931, 0x011935, 0x011937, 0x011938, 0x01193d, 0x01193d, 0x01193f, 0x011942, 0x011944, 0x011946, 0x011950, 0x011959, 0x0119a0, 0x0119a7, - 0x0119aa, 0x0119d3, 0x0119dc, 0x0119df, 0x0119e1, 0x0119e4, 0x011a00, 0x011a00, 0x011a0b, 0x011a32, 0x011a39, 0x011a3a, 0x011a3f, 0x011a46, 0x011a50, 0x011a50, 0x011a57, - 0x011a58, 0x011a5c, 0x011a89, 0x011a97, 0x011a97, 0x011a9a, 0x011aa2, 0x011ac0, 0x011af8, 0x011c00, 0x011c08, 0x011c0a, 0x011c2f, 0x011c3e, 0x011c3e, 0x011c40, 0x011c45, - 0x011c50, 0x011c6c, 0x011c70, 0x011c8f, 0x011ca9, 0x011ca9, 0x011cb1, 0x011cb1, 0x011cb4, 0x011cb4, 0x011d00, 0x011d06, 0x011d08, 0x011d09, 0x011d0b, 0x011d30, 0x011d46, - 0x011d46, 0x011d50, 0x011d59, 0x011d60, 0x011d65, 0x011d67, 0x011d68, 0x011d6a, 0x011d8e, 0x011d93, 0x011d94, 0x011d96, 0x011d96, 0x011d98, 0x011d98, 0x011da0, 0x011da9, - 0x011ee0, 0x011ef2, 0x011ef5, 0x011ef8, 0x011fb0, 0x011fb0, 0x011fc0, 0x011ff1, 0x011fff, 0x012399, 0x012400, 0x01246e, 0x012470, 0x012474, 0x012480, 0x012543, 0x013000, - 0x01342e, 0x014400, 0x014646, 0x016800, 0x016a38, 0x016a40, 0x016a5e, 0x016a60, 0x016a69, 0x016a6e, 0x016a6f, 0x016ad0, 0x016aed, 0x016af5, 0x016af5, 0x016b00, 0x016b2f, - 0x016b37, 0x016b45, 0x016b50, 0x016b59, 0x016b5b, 0x016b61, 0x016b63, 0x016b77, 0x016b7d, 0x016b8f, 0x016e40, 0x016e9a, 0x016f00, 0x016f4a, 0x016f50, 0x016f87, 0x016f93, - 0x016f9f, 0x016fe0, 0x016fe3, 0x016ff0, 0x016ff1, 0x017000, 0x0187f7, 0x018800, 0x018cd5, 0x018d00, 0x018d08, 0x01b000, 0x01b11e, 0x01b150, 0x01b152, 0x01b164, 0x01b167, - 0x01b170, 0x01b2fb, 0x01bc00, 0x01bc6a, 0x01bc70, 0x01bc7c, 0x01bc80, 0x01bc88, 0x01bc90, 0x01bc99, 0x01bc9c, 0x01bc9c, 0x01bc9f, 0x01bc9f, 0x01d000, 0x01d0f5, 0x01d100, - 0x01d126, 0x01d129, 0x01d164, 0x01d166, 0x01d166, 0x01d16a, 0x01d16d, 0x01d183, 0x01d184, 0x01d18c, 0x01d1a9, 0x01d1ae, 0x01d1e8, 0x01d200, 0x01d241, 0x01d245, 0x01d245, - 0x01d2e0, 0x01d2f3, 0x01d300, 0x01d356, 0x01d360, 0x01d378, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, - 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, - 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d7cb, 0x01d7ce, 0x01d9ff, 0x01da37, 0x01da3a, 0x01da6d, - 0x01da74, 0x01da76, 0x01da83, 0x01da85, 0x01da8b, 0x01e100, 0x01e12c, 0x01e137, 0x01e13d, 0x01e140, 0x01e149, 0x01e14e, 0x01e14f, 0x01e2c0, 0x01e2eb, 0x01e2f0, 0x01e2f9, - 0x01e2ff, 0x01e2ff, 0x01e800, 0x01e8c4, 0x01e8c7, 0x01e8cf, 0x01e900, 0x01e943, 0x01e94b, 0x01e94b, 0x01e950, 0x01e959, 0x01e95e, 0x01e95f, 0x01ec71, 0x01ecb4, 0x01ed01, - 0x01ed3d, 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, 0x01ee39, - 0x01ee3b, 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, 0x01ee57, - 0x01ee57, 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, 0x01ee72, - 0x01ee74, 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, 0x01ee80, 0x01ee89, 0x01ee8b, 0x01ee9b, 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, 0x01eef0, - 0x01eef1, 0x01f000, 0x01f02b, 0x01f030, 0x01f093, 0x01f0a0, 0x01f0ae, 0x01f0b1, 0x01f0bf, 0x01f0c1, 0x01f0cf, 0x01f0d1, 0x01f0f5, 0x01f100, 0x01f1ad, 0x01f1e6, 0x01f202, - 0x01f210, 0x01f23b, 0x01f240, 0x01f248, 0x01f250, 0x01f251, 0x01f260, 0x01f265, 0x01f300, 0x01f6d7, 0x01f6e0, 0x01f6ec, 0x01f6f0, 0x01f6fc, 0x01f700, 0x01f773, 0x01f780, - 0x01f7d8, 0x01f7e0, 0x01f7eb, 0x01f800, 0x01f80b, 0x01f810, 0x01f847, 0x01f850, 0x01f859, 0x01f860, 0x01f887, 0x01f890, 0x01f8ad, 0x01f8b0, 0x01f8b1, 0x01f900, 0x01f978, - 0x01f97a, 0x01f9cb, 0x01f9cd, 0x01fa53, 0x01fa60, 0x01fa6d, 0x01fa70, 0x01fa74, 0x01fa78, 0x01fa7a, 0x01fa80, 0x01fa86, 0x01fa90, 0x01faa8, 0x01fab0, 0x01fab6, 0x01fac0, - 0x01fac2, 0x01fad0, 0x01fad6, 0x01fb00, 0x01fb92, 0x01fb94, 0x01fbca, 0x01fbf0, 0x01fbf9, 0x020000, 0x02a6dd, 0x02a700, 0x02b734, 0x02b740, 0x02b81d, 0x02b820, 0x02cea1, - 0x02ceb0, 0x02ebe0, 0x02f800, 0x02fa1d, 0x030000, 0x03134a)); + 0x0103c8, 0x0103d5, 0x010400, 0x01049d, 0x0104a0, 0x0104a9, 0x0104b0, 0x0104d3, 0x0104d8, 0x0104fb, 0x010500, 0x010527, 0x010530, 0x010563, 0x01056f, 0x01057a, 0x01057c, + 0x01058a, 0x01058c, 0x010592, 0x010594, 0x010595, 0x010597, 0x0105a1, 0x0105a3, 0x0105b1, 0x0105b3, 0x0105b9, 0x0105bb, 0x0105bc, 0x010600, 0x010736, 0x010740, 0x010755, + 0x010760, 0x010767, 0x010780, 0x010785, 0x010787, 0x0107b0, 0x0107b2, 0x0107ba, 0x010800, 0x010805, 0x010808, 0x010808, 0x01080a, 0x010835, 0x010837, 0x010838, 0x01083c, + 0x01083c, 0x01083f, 0x010855, 0x010857, 0x01089e, 0x0108a7, 0x0108af, 0x0108e0, 0x0108f2, 0x0108f4, 0x0108f5, 0x0108fb, 0x01091b, 0x01091f, 0x010939, 0x01093f, 0x01093f, + 0x010980, 0x0109b7, 0x0109bc, 0x0109cf, 0x0109d2, 0x010a00, 0x010a10, 0x010a13, 0x010a15, 0x010a17, 0x010a19, 0x010a35, 0x010a40, 0x010a48, 0x010a50, 0x010a58, 0x010a60, + 0x010a9f, 0x010ac0, 0x010ae4, 0x010aeb, 0x010af6, 0x010b00, 0x010b35, 0x010b39, 0x010b55, 0x010b58, 0x010b72, 0x010b78, 0x010b91, 0x010b99, 0x010b9c, 0x010ba9, 0x010baf, + 0x010c00, 0x010c48, 0x010c80, 0x010cb2, 0x010cc0, 0x010cf2, 0x010cfa, 0x010d23, 0x010d30, 0x010d39, 0x010e60, 0x010e7e, 0x010e80, 0x010ea9, 0x010ead, 0x010ead, 0x010eb0, + 0x010eb1, 0x010f00, 0x010f27, 0x010f30, 0x010f45, 0x010f51, 0x010f59, 0x010f70, 0x010f81, 0x010f86, 0x010f89, 0x010fb0, 0x010fcb, 0x010fe0, 0x010ff6, 0x011000, 0x011000, + 0x011002, 0x011037, 0x011047, 0x01104d, 0x011052, 0x01106f, 0x011071, 0x011072, 0x011075, 0x011075, 0x011082, 0x0110b2, 0x0110b7, 0x0110b8, 0x0110bb, 0x0110bc, 0x0110be, + 0x0110c1, 0x0110d0, 0x0110e8, 0x0110f0, 0x0110f9, 0x011103, 0x011126, 0x01112c, 0x01112c, 0x011136, 0x011147, 0x011150, 0x011172, 0x011174, 0x011176, 0x011182, 0x0111b5, + 0x0111bf, 0x0111c8, 0x0111cd, 0x0111ce, 0x0111d0, 0x0111df, 0x0111e1, 0x0111f4, 0x011200, 0x011211, 0x011213, 0x01122e, 0x011232, 0x011233, 0x011235, 0x011235, 0x011238, + 0x01123d, 0x011280, 0x011286, 0x011288, 0x011288, 0x01128a, 0x01128d, 0x01128f, 0x01129d, 0x01129f, 0x0112a9, 0x0112b0, 0x0112de, 0x0112e0, 0x0112e2, 0x0112f0, 0x0112f9, + 0x011302, 0x011303, 0x011305, 0x01130c, 0x01130f, 0x011310, 0x011313, 0x011328, 0x01132a, 0x011330, 0x011332, 0x011333, 0x011335, 0x011339, 0x01133d, 0x01133d, 0x01133f, + 0x01133f, 0x011341, 0x011344, 0x011347, 0x011348, 0x01134b, 0x01134d, 0x011350, 0x011350, 0x01135d, 0x011363, 0x011400, 0x011437, 0x011440, 0x011441, 0x011445, 0x011445, + 0x011447, 0x01145b, 0x01145d, 0x01145d, 0x01145f, 0x011461, 0x011480, 0x0114af, 0x0114b1, 0x0114b2, 0x0114b9, 0x0114b9, 0x0114bb, 0x0114bc, 0x0114be, 0x0114be, 0x0114c1, + 0x0114c1, 0x0114c4, 0x0114c7, 0x0114d0, 0x0114d9, 0x011580, 0x0115ae, 0x0115b0, 0x0115b1, 0x0115b8, 0x0115bb, 0x0115be, 0x0115be, 0x0115c1, 0x0115db, 0x011600, 0x011632, + 0x01163b, 0x01163c, 0x01163e, 0x01163e, 0x011641, 0x011644, 0x011650, 0x011659, 0x011660, 0x01166c, 0x011680, 0x0116aa, 0x0116ac, 0x0116ac, 0x0116ae, 0x0116af, 0x0116b6, + 0x0116b6, 0x0116b8, 0x0116b9, 0x0116c0, 0x0116c9, 0x011700, 0x01171a, 0x011720, 0x011721, 0x011726, 0x011726, 0x011730, 0x011746, 0x011800, 0x01182e, 0x011838, 0x011838, + 0x01183b, 0x01183b, 0x0118a0, 0x0118f2, 0x0118ff, 0x011906, 0x011909, 0x011909, 0x01190c, 0x011913, 0x011915, 0x011916, 0x011918, 0x01192f, 0x011931, 0x011935, 0x011937, + 0x011938, 0x01193d, 0x01193d, 0x01193f, 0x011942, 0x011944, 0x011946, 0x011950, 0x011959, 0x0119a0, 0x0119a7, 0x0119aa, 0x0119d3, 0x0119dc, 0x0119df, 0x0119e1, 0x0119e4, + 0x011a00, 0x011a00, 0x011a0b, 0x011a32, 0x011a39, 0x011a3a, 0x011a3f, 0x011a46, 0x011a50, 0x011a50, 0x011a57, 0x011a58, 0x011a5c, 0x011a89, 0x011a97, 0x011a97, 0x011a9a, + 0x011aa2, 0x011ab0, 0x011af8, 0x011c00, 0x011c08, 0x011c0a, 0x011c2f, 0x011c3e, 0x011c3e, 0x011c40, 0x011c45, 0x011c50, 0x011c6c, 0x011c70, 0x011c8f, 0x011ca9, 0x011ca9, + 0x011cb1, 0x011cb1, 0x011cb4, 0x011cb4, 0x011d00, 0x011d06, 0x011d08, 0x011d09, 0x011d0b, 0x011d30, 0x011d46, 0x011d46, 0x011d50, 0x011d59, 0x011d60, 0x011d65, 0x011d67, + 0x011d68, 0x011d6a, 0x011d8e, 0x011d93, 0x011d94, 0x011d96, 0x011d96, 0x011d98, 0x011d98, 0x011da0, 0x011da9, 0x011ee0, 0x011ef2, 0x011ef5, 0x011ef8, 0x011fb0, 0x011fb0, + 0x011fc0, 0x011ff1, 0x011fff, 0x012399, 0x012400, 0x01246e, 0x012470, 0x012474, 0x012480, 0x012543, 0x012f90, 0x012ff2, 0x013000, 0x01342e, 0x014400, 0x014646, 0x016800, + 0x016a38, 0x016a40, 0x016a5e, 0x016a60, 0x016a69, 0x016a6e, 0x016abe, 0x016ac0, 0x016ac9, 0x016ad0, 0x016aed, 0x016af5, 0x016af5, 0x016b00, 0x016b2f, 0x016b37, 0x016b45, + 0x016b50, 0x016b59, 0x016b5b, 0x016b61, 0x016b63, 0x016b77, 0x016b7d, 0x016b8f, 0x016e40, 0x016e9a, 0x016f00, 0x016f4a, 0x016f50, 0x016f87, 0x016f93, 0x016f9f, 0x016fe0, + 0x016fe3, 0x016ff0, 0x016ff1, 0x017000, 0x0187f7, 0x018800, 0x018cd5, 0x018d00, 0x018d08, 0x01aff0, 0x01aff3, 0x01aff5, 0x01affb, 0x01affd, 0x01affe, 0x01b000, 0x01b122, + 0x01b150, 0x01b152, 0x01b164, 0x01b167, 0x01b170, 0x01b2fb, 0x01bc00, 0x01bc6a, 0x01bc70, 0x01bc7c, 0x01bc80, 0x01bc88, 0x01bc90, 0x01bc99, 0x01bc9c, 0x01bc9c, 0x01bc9f, + 0x01bc9f, 0x01cf50, 0x01cfc3, 0x01d000, 0x01d0f5, 0x01d100, 0x01d126, 0x01d129, 0x01d164, 0x01d166, 0x01d166, 0x01d16a, 0x01d16d, 0x01d183, 0x01d184, 0x01d18c, 0x01d1a9, + 0x01d1ae, 0x01d1ea, 0x01d200, 0x01d241, 0x01d245, 0x01d245, 0x01d2e0, 0x01d2f3, 0x01d300, 0x01d356, 0x01d360, 0x01d378, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, + 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, + 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, + 0x01d7cb, 0x01d7ce, 0x01d9ff, 0x01da37, 0x01da3a, 0x01da6d, 0x01da74, 0x01da76, 0x01da83, 0x01da85, 0x01da8b, 0x01df00, 0x01df1e, 0x01e100, 0x01e12c, 0x01e137, 0x01e13d, + 0x01e140, 0x01e149, 0x01e14e, 0x01e14f, 0x01e290, 0x01e2ad, 0x01e2c0, 0x01e2eb, 0x01e2f0, 0x01e2f9, 0x01e2ff, 0x01e2ff, 0x01e7e0, 0x01e7e6, 0x01e7e8, 0x01e7eb, 0x01e7ed, + 0x01e7ee, 0x01e7f0, 0x01e7fe, 0x01e800, 0x01e8c4, 0x01e8c7, 0x01e8cf, 0x01e900, 0x01e943, 0x01e94b, 0x01e94b, 0x01e950, 0x01e959, 0x01e95e, 0x01e95f, 0x01ec71, 0x01ecb4, + 0x01ed01, 0x01ed3d, 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, + 0x01ee39, 0x01ee3b, 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, + 0x01ee57, 0x01ee57, 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, + 0x01ee72, 0x01ee74, 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, 0x01ee80, 0x01ee89, 0x01ee8b, 0x01ee9b, 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, + 0x01eef0, 0x01eef1, 0x01f000, 0x01f02b, 0x01f030, 0x01f093, 0x01f0a0, 0x01f0ae, 0x01f0b1, 0x01f0bf, 0x01f0c1, 0x01f0cf, 0x01f0d1, 0x01f0f5, 0x01f100, 0x01f1ad, 0x01f1e6, + 0x01f202, 0x01f210, 0x01f23b, 0x01f240, 0x01f248, 0x01f250, 0x01f251, 0x01f260, 0x01f265, 0x01f300, 0x01f6d7, 0x01f6dd, 0x01f6ec, 0x01f6f0, 0x01f6fc, 0x01f700, 0x01f773, + 0x01f780, 0x01f7d8, 0x01f7e0, 0x01f7eb, 0x01f7f0, 0x01f7f0, 0x01f800, 0x01f80b, 0x01f810, 0x01f847, 0x01f850, 0x01f859, 0x01f860, 0x01f887, 0x01f890, 0x01f8ad, 0x01f8b0, + 0x01f8b1, 0x01f900, 0x01fa53, 0x01fa60, 0x01fa6d, 0x01fa70, 0x01fa74, 0x01fa78, 0x01fa7c, 0x01fa80, 0x01fa86, 0x01fa90, 0x01faac, 0x01fab0, 0x01faba, 0x01fac0, 0x01fac5, + 0x01fad0, 0x01fad9, 0x01fae0, 0x01fae7, 0x01faf0, 0x01faf6, 0x01fb00, 0x01fb92, 0x01fb94, 0x01fbca, 0x01fbf0, 0x01fbf9, 0x020000, 0x02a6df, 0x02a700, 0x02b738, 0x02b740, + 0x02b81d, 0x02b820, 0x02cea1, 0x02ceb0, 0x02ebe0, 0x02f800, 0x02fa1d, 0x030000, 0x03134a)); } private static void populateGR_EXT() { SET_ENCODINGS.put("Gr_Ext", CodePointSet.createNoDedup(0x000300, 0x00036f, 0x000483, 0x000489, 0x000591, 0x0005bd, 0x0005bf, 0x0005bf, 0x0005c1, 0x0005c2, 0x0005c4, 0x0005c5, 0x0005c7, 0x0005c7, 0x000610, 0x00061a, 0x00064b, 0x00065f, 0x000670, 0x000670, 0x0006d6, 0x0006dc, 0x0006df, 0x0006e4, 0x0006e7, 0x0006e8, 0x0006ea, 0x0006ed, 0x000711, 0x000711, 0x000730, 0x00074a, 0x0007a6, 0x0007b0, 0x0007eb, 0x0007f3, 0x0007fd, 0x0007fd, 0x000816, 0x000819, 0x00081b, 0x000823, 0x000825, 0x000827, 0x000829, 0x00082d, 0x000859, - 0x00085b, 0x0008d3, 0x0008e1, 0x0008e3, 0x000902, 0x00093a, 0x00093a, 0x00093c, 0x00093c, 0x000941, 0x000948, 0x00094d, 0x00094d, 0x000951, 0x000957, 0x000962, 0x000963, - 0x000981, 0x000981, 0x0009bc, 0x0009bc, 0x0009be, 0x0009be, 0x0009c1, 0x0009c4, 0x0009cd, 0x0009cd, 0x0009d7, 0x0009d7, 0x0009e2, 0x0009e3, 0x0009fe, 0x0009fe, 0x000a01, - 0x000a02, 0x000a3c, 0x000a3c, 0x000a41, 0x000a42, 0x000a47, 0x000a48, 0x000a4b, 0x000a4d, 0x000a51, 0x000a51, 0x000a70, 0x000a71, 0x000a75, 0x000a75, 0x000a81, 0x000a82, - 0x000abc, 0x000abc, 0x000ac1, 0x000ac5, 0x000ac7, 0x000ac8, 0x000acd, 0x000acd, 0x000ae2, 0x000ae3, 0x000afa, 0x000aff, 0x000b01, 0x000b01, 0x000b3c, 0x000b3c, 0x000b3e, - 0x000b3f, 0x000b41, 0x000b44, 0x000b4d, 0x000b4d, 0x000b55, 0x000b57, 0x000b62, 0x000b63, 0x000b82, 0x000b82, 0x000bbe, 0x000bbe, 0x000bc0, 0x000bc0, 0x000bcd, 0x000bcd, - 0x000bd7, 0x000bd7, 0x000c00, 0x000c00, 0x000c04, 0x000c04, 0x000c3e, 0x000c40, 0x000c46, 0x000c48, 0x000c4a, 0x000c4d, 0x000c55, 0x000c56, 0x000c62, 0x000c63, 0x000c81, - 0x000c81, 0x000cbc, 0x000cbc, 0x000cbf, 0x000cbf, 0x000cc2, 0x000cc2, 0x000cc6, 0x000cc6, 0x000ccc, 0x000ccd, 0x000cd5, 0x000cd6, 0x000ce2, 0x000ce3, 0x000d00, 0x000d01, - 0x000d3b, 0x000d3c, 0x000d3e, 0x000d3e, 0x000d41, 0x000d44, 0x000d4d, 0x000d4d, 0x000d57, 0x000d57, 0x000d62, 0x000d63, 0x000d81, 0x000d81, 0x000dca, 0x000dca, 0x000dcf, - 0x000dcf, 0x000dd2, 0x000dd4, 0x000dd6, 0x000dd6, 0x000ddf, 0x000ddf, 0x000e31, 0x000e31, 0x000e34, 0x000e3a, 0x000e47, 0x000e4e, 0x000eb1, 0x000eb1, 0x000eb4, 0x000ebc, - 0x000ec8, 0x000ecd, 0x000f18, 0x000f19, 0x000f35, 0x000f35, 0x000f37, 0x000f37, 0x000f39, 0x000f39, 0x000f71, 0x000f7e, 0x000f80, 0x000f84, 0x000f86, 0x000f87, 0x000f8d, - 0x000f97, 0x000f99, 0x000fbc, 0x000fc6, 0x000fc6, 0x00102d, 0x001030, 0x001032, 0x001037, 0x001039, 0x00103a, 0x00103d, 0x00103e, 0x001058, 0x001059, 0x00105e, 0x001060, - 0x001071, 0x001074, 0x001082, 0x001082, 0x001085, 0x001086, 0x00108d, 0x00108d, 0x00109d, 0x00109d, 0x00135d, 0x00135f, 0x001712, 0x001714, 0x001732, 0x001734, 0x001752, - 0x001753, 0x001772, 0x001773, 0x0017b4, 0x0017b5, 0x0017b7, 0x0017bd, 0x0017c6, 0x0017c6, 0x0017c9, 0x0017d3, 0x0017dd, 0x0017dd, 0x00180b, 0x00180d, 0x001885, 0x001886, - 0x0018a9, 0x0018a9, 0x001920, 0x001922, 0x001927, 0x001928, 0x001932, 0x001932, 0x001939, 0x00193b, 0x001a17, 0x001a18, 0x001a1b, 0x001a1b, 0x001a56, 0x001a56, 0x001a58, - 0x001a5e, 0x001a60, 0x001a60, 0x001a62, 0x001a62, 0x001a65, 0x001a6c, 0x001a73, 0x001a7c, 0x001a7f, 0x001a7f, 0x001ab0, 0x001ac0, 0x001b00, 0x001b03, 0x001b34, 0x001b3a, - 0x001b3c, 0x001b3c, 0x001b42, 0x001b42, 0x001b6b, 0x001b73, 0x001b80, 0x001b81, 0x001ba2, 0x001ba5, 0x001ba8, 0x001ba9, 0x001bab, 0x001bad, 0x001be6, 0x001be6, 0x001be8, - 0x001be9, 0x001bed, 0x001bed, 0x001bef, 0x001bf1, 0x001c2c, 0x001c33, 0x001c36, 0x001c37, 0x001cd0, 0x001cd2, 0x001cd4, 0x001ce0, 0x001ce2, 0x001ce8, 0x001ced, 0x001ced, - 0x001cf4, 0x001cf4, 0x001cf8, 0x001cf9, 0x001dc0, 0x001df9, 0x001dfb, 0x001dff, 0x00200c, 0x00200c, 0x0020d0, 0x0020f0, 0x002cef, 0x002cf1, 0x002d7f, 0x002d7f, 0x002de0, - 0x002dff, 0x00302a, 0x00302f, 0x003099, 0x00309a, 0x00a66f, 0x00a672, 0x00a674, 0x00a67d, 0x00a69e, 0x00a69f, 0x00a6f0, 0x00a6f1, 0x00a802, 0x00a802, 0x00a806, 0x00a806, - 0x00a80b, 0x00a80b, 0x00a825, 0x00a826, 0x00a82c, 0x00a82c, 0x00a8c4, 0x00a8c5, 0x00a8e0, 0x00a8f1, 0x00a8ff, 0x00a8ff, 0x00a926, 0x00a92d, 0x00a947, 0x00a951, 0x00a980, - 0x00a982, 0x00a9b3, 0x00a9b3, 0x00a9b6, 0x00a9b9, 0x00a9bc, 0x00a9bd, 0x00a9e5, 0x00a9e5, 0x00aa29, 0x00aa2e, 0x00aa31, 0x00aa32, 0x00aa35, 0x00aa36, 0x00aa43, 0x00aa43, - 0x00aa4c, 0x00aa4c, 0x00aa7c, 0x00aa7c, 0x00aab0, 0x00aab0, 0x00aab2, 0x00aab4, 0x00aab7, 0x00aab8, 0x00aabe, 0x00aabf, 0x00aac1, 0x00aac1, 0x00aaec, 0x00aaed, 0x00aaf6, - 0x00aaf6, 0x00abe5, 0x00abe5, 0x00abe8, 0x00abe8, 0x00abed, 0x00abed, 0x00fb1e, 0x00fb1e, 0x00fe00, 0x00fe0f, 0x00fe20, 0x00fe2f, 0x00ff9e, 0x00ff9f, 0x0101fd, 0x0101fd, - 0x0102e0, 0x0102e0, 0x010376, 0x01037a, 0x010a01, 0x010a03, 0x010a05, 0x010a06, 0x010a0c, 0x010a0f, 0x010a38, 0x010a3a, 0x010a3f, 0x010a3f, 0x010ae5, 0x010ae6, 0x010d24, - 0x010d27, 0x010eab, 0x010eac, 0x010f46, 0x010f50, 0x011001, 0x011001, 0x011038, 0x011046, 0x01107f, 0x011081, 0x0110b3, 0x0110b6, 0x0110b9, 0x0110ba, 0x011100, 0x011102, - 0x011127, 0x01112b, 0x01112d, 0x011134, 0x011173, 0x011173, 0x011180, 0x011181, 0x0111b6, 0x0111be, 0x0111c9, 0x0111cc, 0x0111cf, 0x0111cf, 0x01122f, 0x011231, 0x011234, - 0x011234, 0x011236, 0x011237, 0x01123e, 0x01123e, 0x0112df, 0x0112df, 0x0112e3, 0x0112ea, 0x011300, 0x011301, 0x01133b, 0x01133c, 0x01133e, 0x01133e, 0x011340, 0x011340, - 0x011357, 0x011357, 0x011366, 0x01136c, 0x011370, 0x011374, 0x011438, 0x01143f, 0x011442, 0x011444, 0x011446, 0x011446, 0x01145e, 0x01145e, 0x0114b0, 0x0114b0, 0x0114b3, - 0x0114b8, 0x0114ba, 0x0114ba, 0x0114bd, 0x0114bd, 0x0114bf, 0x0114c0, 0x0114c2, 0x0114c3, 0x0115af, 0x0115af, 0x0115b2, 0x0115b5, 0x0115bc, 0x0115bd, 0x0115bf, 0x0115c0, - 0x0115dc, 0x0115dd, 0x011633, 0x01163a, 0x01163d, 0x01163d, 0x01163f, 0x011640, 0x0116ab, 0x0116ab, 0x0116ad, 0x0116ad, 0x0116b0, 0x0116b5, 0x0116b7, 0x0116b7, 0x01171d, - 0x01171f, 0x011722, 0x011725, 0x011727, 0x01172b, 0x01182f, 0x011837, 0x011839, 0x01183a, 0x011930, 0x011930, 0x01193b, 0x01193c, 0x01193e, 0x01193e, 0x011943, 0x011943, - 0x0119d4, 0x0119d7, 0x0119da, 0x0119db, 0x0119e0, 0x0119e0, 0x011a01, 0x011a0a, 0x011a33, 0x011a38, 0x011a3b, 0x011a3e, 0x011a47, 0x011a47, 0x011a51, 0x011a56, 0x011a59, - 0x011a5b, 0x011a8a, 0x011a96, 0x011a98, 0x011a99, 0x011c30, 0x011c36, 0x011c38, 0x011c3d, 0x011c3f, 0x011c3f, 0x011c92, 0x011ca7, 0x011caa, 0x011cb0, 0x011cb2, 0x011cb3, - 0x011cb5, 0x011cb6, 0x011d31, 0x011d36, 0x011d3a, 0x011d3a, 0x011d3c, 0x011d3d, 0x011d3f, 0x011d45, 0x011d47, 0x011d47, 0x011d90, 0x011d91, 0x011d95, 0x011d95, 0x011d97, - 0x011d97, 0x011ef3, 0x011ef4, 0x016af0, 0x016af4, 0x016b30, 0x016b36, 0x016f4f, 0x016f4f, 0x016f8f, 0x016f92, 0x016fe4, 0x016fe4, 0x01bc9d, 0x01bc9e, 0x01d165, 0x01d165, - 0x01d167, 0x01d169, 0x01d16e, 0x01d172, 0x01d17b, 0x01d182, 0x01d185, 0x01d18b, 0x01d1aa, 0x01d1ad, 0x01d242, 0x01d244, 0x01da00, 0x01da36, 0x01da3b, 0x01da6c, 0x01da75, - 0x01da75, 0x01da84, 0x01da84, 0x01da9b, 0x01da9f, 0x01daa1, 0x01daaf, 0x01e000, 0x01e006, 0x01e008, 0x01e018, 0x01e01b, 0x01e021, 0x01e023, 0x01e024, 0x01e026, 0x01e02a, - 0x01e130, 0x01e136, 0x01e2ec, 0x01e2ef, 0x01e8d0, 0x01e8d6, 0x01e944, 0x01e94a, 0x0e0020, 0x0e007f, 0x0e0100, 0x0e01ef)); + 0x00085b, 0x000898, 0x00089f, 0x0008ca, 0x0008e1, 0x0008e3, 0x000902, 0x00093a, 0x00093a, 0x00093c, 0x00093c, 0x000941, 0x000948, 0x00094d, 0x00094d, 0x000951, 0x000957, + 0x000962, 0x000963, 0x000981, 0x000981, 0x0009bc, 0x0009bc, 0x0009be, 0x0009be, 0x0009c1, 0x0009c4, 0x0009cd, 0x0009cd, 0x0009d7, 0x0009d7, 0x0009e2, 0x0009e3, 0x0009fe, + 0x0009fe, 0x000a01, 0x000a02, 0x000a3c, 0x000a3c, 0x000a41, 0x000a42, 0x000a47, 0x000a48, 0x000a4b, 0x000a4d, 0x000a51, 0x000a51, 0x000a70, 0x000a71, 0x000a75, 0x000a75, + 0x000a81, 0x000a82, 0x000abc, 0x000abc, 0x000ac1, 0x000ac5, 0x000ac7, 0x000ac8, 0x000acd, 0x000acd, 0x000ae2, 0x000ae3, 0x000afa, 0x000aff, 0x000b01, 0x000b01, 0x000b3c, + 0x000b3c, 0x000b3e, 0x000b3f, 0x000b41, 0x000b44, 0x000b4d, 0x000b4d, 0x000b55, 0x000b57, 0x000b62, 0x000b63, 0x000b82, 0x000b82, 0x000bbe, 0x000bbe, 0x000bc0, 0x000bc0, + 0x000bcd, 0x000bcd, 0x000bd7, 0x000bd7, 0x000c00, 0x000c00, 0x000c04, 0x000c04, 0x000c3c, 0x000c3c, 0x000c3e, 0x000c40, 0x000c46, 0x000c48, 0x000c4a, 0x000c4d, 0x000c55, + 0x000c56, 0x000c62, 0x000c63, 0x000c81, 0x000c81, 0x000cbc, 0x000cbc, 0x000cbf, 0x000cbf, 0x000cc2, 0x000cc2, 0x000cc6, 0x000cc6, 0x000ccc, 0x000ccd, 0x000cd5, 0x000cd6, + 0x000ce2, 0x000ce3, 0x000d00, 0x000d01, 0x000d3b, 0x000d3c, 0x000d3e, 0x000d3e, 0x000d41, 0x000d44, 0x000d4d, 0x000d4d, 0x000d57, 0x000d57, 0x000d62, 0x000d63, 0x000d81, + 0x000d81, 0x000dca, 0x000dca, 0x000dcf, 0x000dcf, 0x000dd2, 0x000dd4, 0x000dd6, 0x000dd6, 0x000ddf, 0x000ddf, 0x000e31, 0x000e31, 0x000e34, 0x000e3a, 0x000e47, 0x000e4e, + 0x000eb1, 0x000eb1, 0x000eb4, 0x000ebc, 0x000ec8, 0x000ecd, 0x000f18, 0x000f19, 0x000f35, 0x000f35, 0x000f37, 0x000f37, 0x000f39, 0x000f39, 0x000f71, 0x000f7e, 0x000f80, + 0x000f84, 0x000f86, 0x000f87, 0x000f8d, 0x000f97, 0x000f99, 0x000fbc, 0x000fc6, 0x000fc6, 0x00102d, 0x001030, 0x001032, 0x001037, 0x001039, 0x00103a, 0x00103d, 0x00103e, + 0x001058, 0x001059, 0x00105e, 0x001060, 0x001071, 0x001074, 0x001082, 0x001082, 0x001085, 0x001086, 0x00108d, 0x00108d, 0x00109d, 0x00109d, 0x00135d, 0x00135f, 0x001712, + 0x001714, 0x001732, 0x001733, 0x001752, 0x001753, 0x001772, 0x001773, 0x0017b4, 0x0017b5, 0x0017b7, 0x0017bd, 0x0017c6, 0x0017c6, 0x0017c9, 0x0017d3, 0x0017dd, 0x0017dd, + 0x00180b, 0x00180d, 0x00180f, 0x00180f, 0x001885, 0x001886, 0x0018a9, 0x0018a9, 0x001920, 0x001922, 0x001927, 0x001928, 0x001932, 0x001932, 0x001939, 0x00193b, 0x001a17, + 0x001a18, 0x001a1b, 0x001a1b, 0x001a56, 0x001a56, 0x001a58, 0x001a5e, 0x001a60, 0x001a60, 0x001a62, 0x001a62, 0x001a65, 0x001a6c, 0x001a73, 0x001a7c, 0x001a7f, 0x001a7f, + 0x001ab0, 0x001ace, 0x001b00, 0x001b03, 0x001b34, 0x001b3a, 0x001b3c, 0x001b3c, 0x001b42, 0x001b42, 0x001b6b, 0x001b73, 0x001b80, 0x001b81, 0x001ba2, 0x001ba5, 0x001ba8, + 0x001ba9, 0x001bab, 0x001bad, 0x001be6, 0x001be6, 0x001be8, 0x001be9, 0x001bed, 0x001bed, 0x001bef, 0x001bf1, 0x001c2c, 0x001c33, 0x001c36, 0x001c37, 0x001cd0, 0x001cd2, + 0x001cd4, 0x001ce0, 0x001ce2, 0x001ce8, 0x001ced, 0x001ced, 0x001cf4, 0x001cf4, 0x001cf8, 0x001cf9, 0x001dc0, 0x001dff, 0x00200c, 0x00200c, 0x0020d0, 0x0020f0, 0x002cef, + 0x002cf1, 0x002d7f, 0x002d7f, 0x002de0, 0x002dff, 0x00302a, 0x00302f, 0x003099, 0x00309a, 0x00a66f, 0x00a672, 0x00a674, 0x00a67d, 0x00a69e, 0x00a69f, 0x00a6f0, 0x00a6f1, + 0x00a802, 0x00a802, 0x00a806, 0x00a806, 0x00a80b, 0x00a80b, 0x00a825, 0x00a826, 0x00a82c, 0x00a82c, 0x00a8c4, 0x00a8c5, 0x00a8e0, 0x00a8f1, 0x00a8ff, 0x00a8ff, 0x00a926, + 0x00a92d, 0x00a947, 0x00a951, 0x00a980, 0x00a982, 0x00a9b3, 0x00a9b3, 0x00a9b6, 0x00a9b9, 0x00a9bc, 0x00a9bd, 0x00a9e5, 0x00a9e5, 0x00aa29, 0x00aa2e, 0x00aa31, 0x00aa32, + 0x00aa35, 0x00aa36, 0x00aa43, 0x00aa43, 0x00aa4c, 0x00aa4c, 0x00aa7c, 0x00aa7c, 0x00aab0, 0x00aab0, 0x00aab2, 0x00aab4, 0x00aab7, 0x00aab8, 0x00aabe, 0x00aabf, 0x00aac1, + 0x00aac1, 0x00aaec, 0x00aaed, 0x00aaf6, 0x00aaf6, 0x00abe5, 0x00abe5, 0x00abe8, 0x00abe8, 0x00abed, 0x00abed, 0x00fb1e, 0x00fb1e, 0x00fe00, 0x00fe0f, 0x00fe20, 0x00fe2f, + 0x00ff9e, 0x00ff9f, 0x0101fd, 0x0101fd, 0x0102e0, 0x0102e0, 0x010376, 0x01037a, 0x010a01, 0x010a03, 0x010a05, 0x010a06, 0x010a0c, 0x010a0f, 0x010a38, 0x010a3a, 0x010a3f, + 0x010a3f, 0x010ae5, 0x010ae6, 0x010d24, 0x010d27, 0x010eab, 0x010eac, 0x010f46, 0x010f50, 0x010f82, 0x010f85, 0x011001, 0x011001, 0x011038, 0x011046, 0x011070, 0x011070, + 0x011073, 0x011074, 0x01107f, 0x011081, 0x0110b3, 0x0110b6, 0x0110b9, 0x0110ba, 0x0110c2, 0x0110c2, 0x011100, 0x011102, 0x011127, 0x01112b, 0x01112d, 0x011134, 0x011173, + 0x011173, 0x011180, 0x011181, 0x0111b6, 0x0111be, 0x0111c9, 0x0111cc, 0x0111cf, 0x0111cf, 0x01122f, 0x011231, 0x011234, 0x011234, 0x011236, 0x011237, 0x01123e, 0x01123e, + 0x0112df, 0x0112df, 0x0112e3, 0x0112ea, 0x011300, 0x011301, 0x01133b, 0x01133c, 0x01133e, 0x01133e, 0x011340, 0x011340, 0x011357, 0x011357, 0x011366, 0x01136c, 0x011370, + 0x011374, 0x011438, 0x01143f, 0x011442, 0x011444, 0x011446, 0x011446, 0x01145e, 0x01145e, 0x0114b0, 0x0114b0, 0x0114b3, 0x0114b8, 0x0114ba, 0x0114ba, 0x0114bd, 0x0114bd, + 0x0114bf, 0x0114c0, 0x0114c2, 0x0114c3, 0x0115af, 0x0115af, 0x0115b2, 0x0115b5, 0x0115bc, 0x0115bd, 0x0115bf, 0x0115c0, 0x0115dc, 0x0115dd, 0x011633, 0x01163a, 0x01163d, + 0x01163d, 0x01163f, 0x011640, 0x0116ab, 0x0116ab, 0x0116ad, 0x0116ad, 0x0116b0, 0x0116b5, 0x0116b7, 0x0116b7, 0x01171d, 0x01171f, 0x011722, 0x011725, 0x011727, 0x01172b, + 0x01182f, 0x011837, 0x011839, 0x01183a, 0x011930, 0x011930, 0x01193b, 0x01193c, 0x01193e, 0x01193e, 0x011943, 0x011943, 0x0119d4, 0x0119d7, 0x0119da, 0x0119db, 0x0119e0, + 0x0119e0, 0x011a01, 0x011a0a, 0x011a33, 0x011a38, 0x011a3b, 0x011a3e, 0x011a47, 0x011a47, 0x011a51, 0x011a56, 0x011a59, 0x011a5b, 0x011a8a, 0x011a96, 0x011a98, 0x011a99, + 0x011c30, 0x011c36, 0x011c38, 0x011c3d, 0x011c3f, 0x011c3f, 0x011c92, 0x011ca7, 0x011caa, 0x011cb0, 0x011cb2, 0x011cb3, 0x011cb5, 0x011cb6, 0x011d31, 0x011d36, 0x011d3a, + 0x011d3a, 0x011d3c, 0x011d3d, 0x011d3f, 0x011d45, 0x011d47, 0x011d47, 0x011d90, 0x011d91, 0x011d95, 0x011d95, 0x011d97, 0x011d97, 0x011ef3, 0x011ef4, 0x016af0, 0x016af4, + 0x016b30, 0x016b36, 0x016f4f, 0x016f4f, 0x016f8f, 0x016f92, 0x016fe4, 0x016fe4, 0x01bc9d, 0x01bc9e, 0x01cf00, 0x01cf2d, 0x01cf30, 0x01cf46, 0x01d165, 0x01d165, 0x01d167, + 0x01d169, 0x01d16e, 0x01d172, 0x01d17b, 0x01d182, 0x01d185, 0x01d18b, 0x01d1aa, 0x01d1ad, 0x01d242, 0x01d244, 0x01da00, 0x01da36, 0x01da3b, 0x01da6c, 0x01da75, 0x01da75, + 0x01da84, 0x01da84, 0x01da9b, 0x01da9f, 0x01daa1, 0x01daaf, 0x01e000, 0x01e006, 0x01e008, 0x01e018, 0x01e01b, 0x01e021, 0x01e023, 0x01e024, 0x01e026, 0x01e02a, 0x01e130, + 0x01e136, 0x01e2ae, 0x01e2ae, 0x01e2ec, 0x01e2ef, 0x01e8d0, 0x01e8d6, 0x01e944, 0x01e94a, 0x0e0020, 0x0e007f, 0x0e0100, 0x0e01ef)); } private static void populateHEX() { @@ -1932,7 +1972,7 @@ private static void populateIDC() { 0x000483, 0x000487, 0x00048a, 0x00052f, 0x000531, 0x000556, 0x000559, 0x000559, 0x000560, 0x000588, 0x000591, 0x0005bd, 0x0005bf, 0x0005bf, 0x0005c1, 0x0005c2, 0x0005c4, 0x0005c5, 0x0005c7, 0x0005c7, 0x0005d0, 0x0005ea, 0x0005ef, 0x0005f2, 0x000610, 0x00061a, 0x000620, 0x000669, 0x00066e, 0x0006d3, 0x0006d5, 0x0006dc, 0x0006df, 0x0006e8, 0x0006ea, 0x0006fc, 0x0006ff, 0x0006ff, 0x000710, 0x00074a, 0x00074d, 0x0007b1, 0x0007c0, 0x0007f5, 0x0007fa, 0x0007fa, 0x0007fd, 0x0007fd, 0x000800, 0x00082d, 0x000840, - 0x00085b, 0x000860, 0x00086a, 0x0008a0, 0x0008b4, 0x0008b6, 0x0008c7, 0x0008d3, 0x0008e1, 0x0008e3, 0x000963, 0x000966, 0x00096f, 0x000971, 0x000983, 0x000985, 0x00098c, + 0x00085b, 0x000860, 0x00086a, 0x000870, 0x000887, 0x000889, 0x00088e, 0x000898, 0x0008e1, 0x0008e3, 0x000963, 0x000966, 0x00096f, 0x000971, 0x000983, 0x000985, 0x00098c, 0x00098f, 0x000990, 0x000993, 0x0009a8, 0x0009aa, 0x0009b0, 0x0009b2, 0x0009b2, 0x0009b6, 0x0009b9, 0x0009bc, 0x0009c4, 0x0009c7, 0x0009c8, 0x0009cb, 0x0009ce, 0x0009d7, 0x0009d7, 0x0009dc, 0x0009dd, 0x0009df, 0x0009e3, 0x0009e6, 0x0009f1, 0x0009fc, 0x0009fc, 0x0009fe, 0x0009fe, 0x000a01, 0x000a03, 0x000a05, 0x000a0a, 0x000a0f, 0x000a10, 0x000a13, 0x000a28, 0x000a2a, 0x000a30, 0x000a32, 0x000a33, 0x000a35, 0x000a36, 0x000a38, 0x000a39, 0x000a3c, 0x000a3c, 0x000a3e, 0x000a42, 0x000a47, 0x000a48, 0x000a4b, @@ -1942,77 +1982,80 @@ private static void populateIDC() { 0x000b3c, 0x000b44, 0x000b47, 0x000b48, 0x000b4b, 0x000b4d, 0x000b55, 0x000b57, 0x000b5c, 0x000b5d, 0x000b5f, 0x000b63, 0x000b66, 0x000b6f, 0x000b71, 0x000b71, 0x000b82, 0x000b83, 0x000b85, 0x000b8a, 0x000b8e, 0x000b90, 0x000b92, 0x000b95, 0x000b99, 0x000b9a, 0x000b9c, 0x000b9c, 0x000b9e, 0x000b9f, 0x000ba3, 0x000ba4, 0x000ba8, 0x000baa, 0x000bae, 0x000bb9, 0x000bbe, 0x000bc2, 0x000bc6, 0x000bc8, 0x000bca, 0x000bcd, 0x000bd0, 0x000bd0, 0x000bd7, 0x000bd7, 0x000be6, 0x000bef, 0x000c00, 0x000c0c, 0x000c0e, - 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3d, 0x000c44, 0x000c46, 0x000c48, 0x000c4a, 0x000c4d, 0x000c55, 0x000c56, 0x000c58, 0x000c5a, 0x000c60, 0x000c63, - 0x000c66, 0x000c6f, 0x000c80, 0x000c83, 0x000c85, 0x000c8c, 0x000c8e, 0x000c90, 0x000c92, 0x000ca8, 0x000caa, 0x000cb3, 0x000cb5, 0x000cb9, 0x000cbc, 0x000cc4, 0x000cc6, - 0x000cc8, 0x000cca, 0x000ccd, 0x000cd5, 0x000cd6, 0x000cde, 0x000cde, 0x000ce0, 0x000ce3, 0x000ce6, 0x000cef, 0x000cf1, 0x000cf2, 0x000d00, 0x000d0c, 0x000d0e, 0x000d10, - 0x000d12, 0x000d44, 0x000d46, 0x000d48, 0x000d4a, 0x000d4e, 0x000d54, 0x000d57, 0x000d5f, 0x000d63, 0x000d66, 0x000d6f, 0x000d7a, 0x000d7f, 0x000d81, 0x000d83, 0x000d85, - 0x000d96, 0x000d9a, 0x000db1, 0x000db3, 0x000dbb, 0x000dbd, 0x000dbd, 0x000dc0, 0x000dc6, 0x000dca, 0x000dca, 0x000dcf, 0x000dd4, 0x000dd6, 0x000dd6, 0x000dd8, 0x000ddf, - 0x000de6, 0x000def, 0x000df2, 0x000df3, 0x000e01, 0x000e3a, 0x000e40, 0x000e4e, 0x000e50, 0x000e59, 0x000e81, 0x000e82, 0x000e84, 0x000e84, 0x000e86, 0x000e8a, 0x000e8c, - 0x000ea3, 0x000ea5, 0x000ea5, 0x000ea7, 0x000ebd, 0x000ec0, 0x000ec4, 0x000ec6, 0x000ec6, 0x000ec8, 0x000ecd, 0x000ed0, 0x000ed9, 0x000edc, 0x000edf, 0x000f00, 0x000f00, - 0x000f18, 0x000f19, 0x000f20, 0x000f29, 0x000f35, 0x000f35, 0x000f37, 0x000f37, 0x000f39, 0x000f39, 0x000f3e, 0x000f47, 0x000f49, 0x000f6c, 0x000f71, 0x000f84, 0x000f86, - 0x000f97, 0x000f99, 0x000fbc, 0x000fc6, 0x000fc6, 0x001000, 0x001049, 0x001050, 0x00109d, 0x0010a0, 0x0010c5, 0x0010c7, 0x0010c7, 0x0010cd, 0x0010cd, 0x0010d0, 0x0010fa, - 0x0010fc, 0x001248, 0x00124a, 0x00124d, 0x001250, 0x001256, 0x001258, 0x001258, 0x00125a, 0x00125d, 0x001260, 0x001288, 0x00128a, 0x00128d, 0x001290, 0x0012b0, 0x0012b2, - 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, 0x0012d8, 0x001310, 0x001312, 0x001315, 0x001318, 0x00135a, 0x00135d, 0x00135f, - 0x001369, 0x001371, 0x001380, 0x00138f, 0x0013a0, 0x0013f5, 0x0013f8, 0x0013fd, 0x001401, 0x00166c, 0x00166f, 0x00167f, 0x001681, 0x00169a, 0x0016a0, 0x0016ea, 0x0016ee, - 0x0016f8, 0x001700, 0x00170c, 0x00170e, 0x001714, 0x001720, 0x001734, 0x001740, 0x001753, 0x001760, 0x00176c, 0x00176e, 0x001770, 0x001772, 0x001773, 0x001780, 0x0017d3, - 0x0017d7, 0x0017d7, 0x0017dc, 0x0017dd, 0x0017e0, 0x0017e9, 0x00180b, 0x00180d, 0x001810, 0x001819, 0x001820, 0x001878, 0x001880, 0x0018aa, 0x0018b0, 0x0018f5, 0x001900, + 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3c, 0x000c44, 0x000c46, 0x000c48, 0x000c4a, 0x000c4d, 0x000c55, 0x000c56, 0x000c58, 0x000c5a, 0x000c5d, 0x000c5d, + 0x000c60, 0x000c63, 0x000c66, 0x000c6f, 0x000c80, 0x000c83, 0x000c85, 0x000c8c, 0x000c8e, 0x000c90, 0x000c92, 0x000ca8, 0x000caa, 0x000cb3, 0x000cb5, 0x000cb9, 0x000cbc, + 0x000cc4, 0x000cc6, 0x000cc8, 0x000cca, 0x000ccd, 0x000cd5, 0x000cd6, 0x000cdd, 0x000cde, 0x000ce0, 0x000ce3, 0x000ce6, 0x000cef, 0x000cf1, 0x000cf2, 0x000d00, 0x000d0c, + 0x000d0e, 0x000d10, 0x000d12, 0x000d44, 0x000d46, 0x000d48, 0x000d4a, 0x000d4e, 0x000d54, 0x000d57, 0x000d5f, 0x000d63, 0x000d66, 0x000d6f, 0x000d7a, 0x000d7f, 0x000d81, + 0x000d83, 0x000d85, 0x000d96, 0x000d9a, 0x000db1, 0x000db3, 0x000dbb, 0x000dbd, 0x000dbd, 0x000dc0, 0x000dc6, 0x000dca, 0x000dca, 0x000dcf, 0x000dd4, 0x000dd6, 0x000dd6, + 0x000dd8, 0x000ddf, 0x000de6, 0x000def, 0x000df2, 0x000df3, 0x000e01, 0x000e3a, 0x000e40, 0x000e4e, 0x000e50, 0x000e59, 0x000e81, 0x000e82, 0x000e84, 0x000e84, 0x000e86, + 0x000e8a, 0x000e8c, 0x000ea3, 0x000ea5, 0x000ea5, 0x000ea7, 0x000ebd, 0x000ec0, 0x000ec4, 0x000ec6, 0x000ec6, 0x000ec8, 0x000ecd, 0x000ed0, 0x000ed9, 0x000edc, 0x000edf, + 0x000f00, 0x000f00, 0x000f18, 0x000f19, 0x000f20, 0x000f29, 0x000f35, 0x000f35, 0x000f37, 0x000f37, 0x000f39, 0x000f39, 0x000f3e, 0x000f47, 0x000f49, 0x000f6c, 0x000f71, + 0x000f84, 0x000f86, 0x000f97, 0x000f99, 0x000fbc, 0x000fc6, 0x000fc6, 0x001000, 0x001049, 0x001050, 0x00109d, 0x0010a0, 0x0010c5, 0x0010c7, 0x0010c7, 0x0010cd, 0x0010cd, + 0x0010d0, 0x0010fa, 0x0010fc, 0x001248, 0x00124a, 0x00124d, 0x001250, 0x001256, 0x001258, 0x001258, 0x00125a, 0x00125d, 0x001260, 0x001288, 0x00128a, 0x00128d, 0x001290, + 0x0012b0, 0x0012b2, 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, 0x0012d8, 0x001310, 0x001312, 0x001315, 0x001318, 0x00135a, + 0x00135d, 0x00135f, 0x001369, 0x001371, 0x001380, 0x00138f, 0x0013a0, 0x0013f5, 0x0013f8, 0x0013fd, 0x001401, 0x00166c, 0x00166f, 0x00167f, 0x001681, 0x00169a, 0x0016a0, + 0x0016ea, 0x0016ee, 0x0016f8, 0x001700, 0x001715, 0x00171f, 0x001734, 0x001740, 0x001753, 0x001760, 0x00176c, 0x00176e, 0x001770, 0x001772, 0x001773, 0x001780, 0x0017d3, + 0x0017d7, 0x0017d7, 0x0017dc, 0x0017dd, 0x0017e0, 0x0017e9, 0x00180b, 0x00180d, 0x00180f, 0x001819, 0x001820, 0x001878, 0x001880, 0x0018aa, 0x0018b0, 0x0018f5, 0x001900, 0x00191e, 0x001920, 0x00192b, 0x001930, 0x00193b, 0x001946, 0x00196d, 0x001970, 0x001974, 0x001980, 0x0019ab, 0x0019b0, 0x0019c9, 0x0019d0, 0x0019da, 0x001a00, 0x001a1b, - 0x001a20, 0x001a5e, 0x001a60, 0x001a7c, 0x001a7f, 0x001a89, 0x001a90, 0x001a99, 0x001aa7, 0x001aa7, 0x001ab0, 0x001abd, 0x001abf, 0x001ac0, 0x001b00, 0x001b4b, 0x001b50, + 0x001a20, 0x001a5e, 0x001a60, 0x001a7c, 0x001a7f, 0x001a89, 0x001a90, 0x001a99, 0x001aa7, 0x001aa7, 0x001ab0, 0x001abd, 0x001abf, 0x001ace, 0x001b00, 0x001b4c, 0x001b50, 0x001b59, 0x001b6b, 0x001b73, 0x001b80, 0x001bf3, 0x001c00, 0x001c37, 0x001c40, 0x001c49, 0x001c4d, 0x001c7d, 0x001c80, 0x001c88, 0x001c90, 0x001cba, 0x001cbd, 0x001cbf, - 0x001cd0, 0x001cd2, 0x001cd4, 0x001cfa, 0x001d00, 0x001df9, 0x001dfb, 0x001f15, 0x001f18, 0x001f1d, 0x001f20, 0x001f45, 0x001f48, 0x001f4d, 0x001f50, 0x001f57, 0x001f59, - 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f7d, 0x001f80, 0x001fb4, 0x001fb6, 0x001fbc, 0x001fbe, 0x001fbe, 0x001fc2, 0x001fc4, 0x001fc6, 0x001fcc, - 0x001fd0, 0x001fd3, 0x001fd6, 0x001fdb, 0x001fe0, 0x001fec, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ffc, 0x00203f, 0x002040, 0x002054, 0x002054, 0x002071, 0x002071, 0x00207f, - 0x00207f, 0x002090, 0x00209c, 0x0020d0, 0x0020dc, 0x0020e1, 0x0020e1, 0x0020e5, 0x0020f0, 0x002102, 0x002102, 0x002107, 0x002107, 0x00210a, 0x002113, 0x002115, 0x002115, - 0x002118, 0x00211d, 0x002124, 0x002124, 0x002126, 0x002126, 0x002128, 0x002128, 0x00212a, 0x002139, 0x00213c, 0x00213f, 0x002145, 0x002149, 0x00214e, 0x00214e, 0x002160, - 0x002188, 0x002c00, 0x002c2e, 0x002c30, 0x002c5e, 0x002c60, 0x002ce4, 0x002ceb, 0x002cf3, 0x002d00, 0x002d25, 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, 0x002d30, 0x002d67, - 0x002d6f, 0x002d6f, 0x002d7f, 0x002d96, 0x002da0, 0x002da6, 0x002da8, 0x002dae, 0x002db0, 0x002db6, 0x002db8, 0x002dbe, 0x002dc0, 0x002dc6, 0x002dc8, 0x002dce, 0x002dd0, - 0x002dd6, 0x002dd8, 0x002dde, 0x002de0, 0x002dff, 0x003005, 0x003007, 0x003021, 0x00302f, 0x003031, 0x003035, 0x003038, 0x00303c, 0x003041, 0x003096, 0x003099, 0x00309f, - 0x0030a1, 0x0030fa, 0x0030fc, 0x0030ff, 0x003105, 0x00312f, 0x003131, 0x00318e, 0x0031a0, 0x0031bf, 0x0031f0, 0x0031ff, 0x003400, 0x004dbf, 0x004e00, 0x009ffc, 0x00a000, - 0x00a48c, 0x00a4d0, 0x00a4fd, 0x00a500, 0x00a60c, 0x00a610, 0x00a62b, 0x00a640, 0x00a66f, 0x00a674, 0x00a67d, 0x00a67f, 0x00a6f1, 0x00a717, 0x00a71f, 0x00a722, 0x00a788, - 0x00a78b, 0x00a7bf, 0x00a7c2, 0x00a7ca, 0x00a7f5, 0x00a827, 0x00a82c, 0x00a82c, 0x00a840, 0x00a873, 0x00a880, 0x00a8c5, 0x00a8d0, 0x00a8d9, 0x00a8e0, 0x00a8f7, 0x00a8fb, - 0x00a8fb, 0x00a8fd, 0x00a92d, 0x00a930, 0x00a953, 0x00a960, 0x00a97c, 0x00a980, 0x00a9c0, 0x00a9cf, 0x00a9d9, 0x00a9e0, 0x00a9fe, 0x00aa00, 0x00aa36, 0x00aa40, 0x00aa4d, - 0x00aa50, 0x00aa59, 0x00aa60, 0x00aa76, 0x00aa7a, 0x00aac2, 0x00aadb, 0x00aadd, 0x00aae0, 0x00aaef, 0x00aaf2, 0x00aaf6, 0x00ab01, 0x00ab06, 0x00ab09, 0x00ab0e, 0x00ab11, - 0x00ab16, 0x00ab20, 0x00ab26, 0x00ab28, 0x00ab2e, 0x00ab30, 0x00ab5a, 0x00ab5c, 0x00ab69, 0x00ab70, 0x00abea, 0x00abec, 0x00abed, 0x00abf0, 0x00abf9, 0x00ac00, 0x00d7a3, - 0x00d7b0, 0x00d7c6, 0x00d7cb, 0x00d7fb, 0x00f900, 0x00fa6d, 0x00fa70, 0x00fad9, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, 0x00fb1d, 0x00fb28, 0x00fb2a, 0x00fb36, 0x00fb38, - 0x00fb3c, 0x00fb3e, 0x00fb3e, 0x00fb40, 0x00fb41, 0x00fb43, 0x00fb44, 0x00fb46, 0x00fbb1, 0x00fbd3, 0x00fd3d, 0x00fd50, 0x00fd8f, 0x00fd92, 0x00fdc7, 0x00fdf0, 0x00fdfb, - 0x00fe00, 0x00fe0f, 0x00fe20, 0x00fe2f, 0x00fe33, 0x00fe34, 0x00fe4d, 0x00fe4f, 0x00fe70, 0x00fe74, 0x00fe76, 0x00fefc, 0x00ff10, 0x00ff19, 0x00ff21, 0x00ff3a, 0x00ff3f, - 0x00ff3f, 0x00ff41, 0x00ff5a, 0x00ff66, 0x00ffbe, 0x00ffc2, 0x00ffc7, 0x00ffca, 0x00ffcf, 0x00ffd2, 0x00ffd7, 0x00ffda, 0x00ffdc, 0x010000, 0x01000b, 0x01000d, 0x010026, - 0x010028, 0x01003a, 0x01003c, 0x01003d, 0x01003f, 0x01004d, 0x010050, 0x01005d, 0x010080, 0x0100fa, 0x010140, 0x010174, 0x0101fd, 0x0101fd, 0x010280, 0x01029c, 0x0102a0, - 0x0102d0, 0x0102e0, 0x0102e0, 0x010300, 0x01031f, 0x01032d, 0x01034a, 0x010350, 0x01037a, 0x010380, 0x01039d, 0x0103a0, 0x0103c3, 0x0103c8, 0x0103cf, 0x0103d1, 0x0103d5, - 0x010400, 0x01049d, 0x0104a0, 0x0104a9, 0x0104b0, 0x0104d3, 0x0104d8, 0x0104fb, 0x010500, 0x010527, 0x010530, 0x010563, 0x010600, 0x010736, 0x010740, 0x010755, 0x010760, - 0x010767, 0x010800, 0x010805, 0x010808, 0x010808, 0x01080a, 0x010835, 0x010837, 0x010838, 0x01083c, 0x01083c, 0x01083f, 0x010855, 0x010860, 0x010876, 0x010880, 0x01089e, - 0x0108e0, 0x0108f2, 0x0108f4, 0x0108f5, 0x010900, 0x010915, 0x010920, 0x010939, 0x010980, 0x0109b7, 0x0109be, 0x0109bf, 0x010a00, 0x010a03, 0x010a05, 0x010a06, 0x010a0c, - 0x010a13, 0x010a15, 0x010a17, 0x010a19, 0x010a35, 0x010a38, 0x010a3a, 0x010a3f, 0x010a3f, 0x010a60, 0x010a7c, 0x010a80, 0x010a9c, 0x010ac0, 0x010ac7, 0x010ac9, 0x010ae6, - 0x010b00, 0x010b35, 0x010b40, 0x010b55, 0x010b60, 0x010b72, 0x010b80, 0x010b91, 0x010c00, 0x010c48, 0x010c80, 0x010cb2, 0x010cc0, 0x010cf2, 0x010d00, 0x010d27, 0x010d30, - 0x010d39, 0x010e80, 0x010ea9, 0x010eab, 0x010eac, 0x010eb0, 0x010eb1, 0x010f00, 0x010f1c, 0x010f27, 0x010f27, 0x010f30, 0x010f50, 0x010fb0, 0x010fc4, 0x010fe0, 0x010ff6, - 0x011000, 0x011046, 0x011066, 0x01106f, 0x01107f, 0x0110ba, 0x0110d0, 0x0110e8, 0x0110f0, 0x0110f9, 0x011100, 0x011134, 0x011136, 0x01113f, 0x011144, 0x011147, 0x011150, - 0x011173, 0x011176, 0x011176, 0x011180, 0x0111c4, 0x0111c9, 0x0111cc, 0x0111ce, 0x0111da, 0x0111dc, 0x0111dc, 0x011200, 0x011211, 0x011213, 0x011237, 0x01123e, 0x01123e, - 0x011280, 0x011286, 0x011288, 0x011288, 0x01128a, 0x01128d, 0x01128f, 0x01129d, 0x01129f, 0x0112a8, 0x0112b0, 0x0112ea, 0x0112f0, 0x0112f9, 0x011300, 0x011303, 0x011305, - 0x01130c, 0x01130f, 0x011310, 0x011313, 0x011328, 0x01132a, 0x011330, 0x011332, 0x011333, 0x011335, 0x011339, 0x01133b, 0x011344, 0x011347, 0x011348, 0x01134b, 0x01134d, - 0x011350, 0x011350, 0x011357, 0x011357, 0x01135d, 0x011363, 0x011366, 0x01136c, 0x011370, 0x011374, 0x011400, 0x01144a, 0x011450, 0x011459, 0x01145e, 0x011461, 0x011480, - 0x0114c5, 0x0114c7, 0x0114c7, 0x0114d0, 0x0114d9, 0x011580, 0x0115b5, 0x0115b8, 0x0115c0, 0x0115d8, 0x0115dd, 0x011600, 0x011640, 0x011644, 0x011644, 0x011650, 0x011659, - 0x011680, 0x0116b8, 0x0116c0, 0x0116c9, 0x011700, 0x01171a, 0x01171d, 0x01172b, 0x011730, 0x011739, 0x011800, 0x01183a, 0x0118a0, 0x0118e9, 0x0118ff, 0x011906, 0x011909, - 0x011909, 0x01190c, 0x011913, 0x011915, 0x011916, 0x011918, 0x011935, 0x011937, 0x011938, 0x01193b, 0x011943, 0x011950, 0x011959, 0x0119a0, 0x0119a7, 0x0119aa, 0x0119d7, - 0x0119da, 0x0119e1, 0x0119e3, 0x0119e4, 0x011a00, 0x011a3e, 0x011a47, 0x011a47, 0x011a50, 0x011a99, 0x011a9d, 0x011a9d, 0x011ac0, 0x011af8, 0x011c00, 0x011c08, 0x011c0a, - 0x011c36, 0x011c38, 0x011c40, 0x011c50, 0x011c59, 0x011c72, 0x011c8f, 0x011c92, 0x011ca7, 0x011ca9, 0x011cb6, 0x011d00, 0x011d06, 0x011d08, 0x011d09, 0x011d0b, 0x011d36, - 0x011d3a, 0x011d3a, 0x011d3c, 0x011d3d, 0x011d3f, 0x011d47, 0x011d50, 0x011d59, 0x011d60, 0x011d65, 0x011d67, 0x011d68, 0x011d6a, 0x011d8e, 0x011d90, 0x011d91, 0x011d93, - 0x011d98, 0x011da0, 0x011da9, 0x011ee0, 0x011ef6, 0x011fb0, 0x011fb0, 0x012000, 0x012399, 0x012400, 0x01246e, 0x012480, 0x012543, 0x013000, 0x01342e, 0x014400, 0x014646, - 0x016800, 0x016a38, 0x016a40, 0x016a5e, 0x016a60, 0x016a69, 0x016ad0, 0x016aed, 0x016af0, 0x016af4, 0x016b00, 0x016b36, 0x016b40, 0x016b43, 0x016b50, 0x016b59, 0x016b63, - 0x016b77, 0x016b7d, 0x016b8f, 0x016e40, 0x016e7f, 0x016f00, 0x016f4a, 0x016f4f, 0x016f87, 0x016f8f, 0x016f9f, 0x016fe0, 0x016fe1, 0x016fe3, 0x016fe4, 0x016ff0, 0x016ff1, - 0x017000, 0x0187f7, 0x018800, 0x018cd5, 0x018d00, 0x018d08, 0x01b000, 0x01b11e, 0x01b150, 0x01b152, 0x01b164, 0x01b167, 0x01b170, 0x01b2fb, 0x01bc00, 0x01bc6a, 0x01bc70, - 0x01bc7c, 0x01bc80, 0x01bc88, 0x01bc90, 0x01bc99, 0x01bc9d, 0x01bc9e, 0x01d165, 0x01d169, 0x01d16d, 0x01d172, 0x01d17b, 0x01d182, 0x01d185, 0x01d18b, 0x01d1aa, 0x01d1ad, - 0x01d242, 0x01d244, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, - 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, - 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d6c0, 0x01d6c2, 0x01d6da, 0x01d6dc, 0x01d6fa, 0x01d6fc, 0x01d714, 0x01d716, 0x01d734, 0x01d736, - 0x01d74e, 0x01d750, 0x01d76e, 0x01d770, 0x01d788, 0x01d78a, 0x01d7a8, 0x01d7aa, 0x01d7c2, 0x01d7c4, 0x01d7cb, 0x01d7ce, 0x01d7ff, 0x01da00, 0x01da36, 0x01da3b, 0x01da6c, - 0x01da75, 0x01da75, 0x01da84, 0x01da84, 0x01da9b, 0x01da9f, 0x01daa1, 0x01daaf, 0x01e000, 0x01e006, 0x01e008, 0x01e018, 0x01e01b, 0x01e021, 0x01e023, 0x01e024, 0x01e026, - 0x01e02a, 0x01e100, 0x01e12c, 0x01e130, 0x01e13d, 0x01e140, 0x01e149, 0x01e14e, 0x01e14e, 0x01e2c0, 0x01e2f9, 0x01e800, 0x01e8c4, 0x01e8d0, 0x01e8d6, 0x01e900, 0x01e94b, - 0x01e950, 0x01e959, 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, - 0x01ee39, 0x01ee3b, 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, - 0x01ee57, 0x01ee57, 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, - 0x01ee72, 0x01ee74, 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, 0x01ee80, 0x01ee89, 0x01ee8b, 0x01ee9b, 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, - 0x01fbf0, 0x01fbf9, 0x020000, 0x02a6dd, 0x02a700, 0x02b734, 0x02b740, 0x02b81d, 0x02b820, 0x02cea1, 0x02ceb0, 0x02ebe0, 0x02f800, 0x02fa1d, 0x030000, 0x03134a, 0x0e0100, - 0x0e01ef)); + 0x001cd0, 0x001cd2, 0x001cd4, 0x001cfa, 0x001d00, 0x001f15, 0x001f18, 0x001f1d, 0x001f20, 0x001f45, 0x001f48, 0x001f4d, 0x001f50, 0x001f57, 0x001f59, 0x001f59, 0x001f5b, + 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f7d, 0x001f80, 0x001fb4, 0x001fb6, 0x001fbc, 0x001fbe, 0x001fbe, 0x001fc2, 0x001fc4, 0x001fc6, 0x001fcc, 0x001fd0, 0x001fd3, + 0x001fd6, 0x001fdb, 0x001fe0, 0x001fec, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ffc, 0x00203f, 0x002040, 0x002054, 0x002054, 0x002071, 0x002071, 0x00207f, 0x00207f, 0x002090, + 0x00209c, 0x0020d0, 0x0020dc, 0x0020e1, 0x0020e1, 0x0020e5, 0x0020f0, 0x002102, 0x002102, 0x002107, 0x002107, 0x00210a, 0x002113, 0x002115, 0x002115, 0x002118, 0x00211d, + 0x002124, 0x002124, 0x002126, 0x002126, 0x002128, 0x002128, 0x00212a, 0x002139, 0x00213c, 0x00213f, 0x002145, 0x002149, 0x00214e, 0x00214e, 0x002160, 0x002188, 0x002c00, + 0x002ce4, 0x002ceb, 0x002cf3, 0x002d00, 0x002d25, 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, 0x002d30, 0x002d67, 0x002d6f, 0x002d6f, 0x002d7f, 0x002d96, 0x002da0, 0x002da6, + 0x002da8, 0x002dae, 0x002db0, 0x002db6, 0x002db8, 0x002dbe, 0x002dc0, 0x002dc6, 0x002dc8, 0x002dce, 0x002dd0, 0x002dd6, 0x002dd8, 0x002dde, 0x002de0, 0x002dff, 0x003005, + 0x003007, 0x003021, 0x00302f, 0x003031, 0x003035, 0x003038, 0x00303c, 0x003041, 0x003096, 0x003099, 0x00309f, 0x0030a1, 0x0030fa, 0x0030fc, 0x0030ff, 0x003105, 0x00312f, + 0x003131, 0x00318e, 0x0031a0, 0x0031bf, 0x0031f0, 0x0031ff, 0x003400, 0x004dbf, 0x004e00, 0x00a48c, 0x00a4d0, 0x00a4fd, 0x00a500, 0x00a60c, 0x00a610, 0x00a62b, 0x00a640, + 0x00a66f, 0x00a674, 0x00a67d, 0x00a67f, 0x00a6f1, 0x00a717, 0x00a71f, 0x00a722, 0x00a788, 0x00a78b, 0x00a7ca, 0x00a7d0, 0x00a7d1, 0x00a7d3, 0x00a7d3, 0x00a7d5, 0x00a7d9, + 0x00a7f2, 0x00a827, 0x00a82c, 0x00a82c, 0x00a840, 0x00a873, 0x00a880, 0x00a8c5, 0x00a8d0, 0x00a8d9, 0x00a8e0, 0x00a8f7, 0x00a8fb, 0x00a8fb, 0x00a8fd, 0x00a92d, 0x00a930, + 0x00a953, 0x00a960, 0x00a97c, 0x00a980, 0x00a9c0, 0x00a9cf, 0x00a9d9, 0x00a9e0, 0x00a9fe, 0x00aa00, 0x00aa36, 0x00aa40, 0x00aa4d, 0x00aa50, 0x00aa59, 0x00aa60, 0x00aa76, + 0x00aa7a, 0x00aac2, 0x00aadb, 0x00aadd, 0x00aae0, 0x00aaef, 0x00aaf2, 0x00aaf6, 0x00ab01, 0x00ab06, 0x00ab09, 0x00ab0e, 0x00ab11, 0x00ab16, 0x00ab20, 0x00ab26, 0x00ab28, + 0x00ab2e, 0x00ab30, 0x00ab5a, 0x00ab5c, 0x00ab69, 0x00ab70, 0x00abea, 0x00abec, 0x00abed, 0x00abf0, 0x00abf9, 0x00ac00, 0x00d7a3, 0x00d7b0, 0x00d7c6, 0x00d7cb, 0x00d7fb, + 0x00f900, 0x00fa6d, 0x00fa70, 0x00fad9, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, 0x00fb1d, 0x00fb28, 0x00fb2a, 0x00fb36, 0x00fb38, 0x00fb3c, 0x00fb3e, 0x00fb3e, 0x00fb40, + 0x00fb41, 0x00fb43, 0x00fb44, 0x00fb46, 0x00fbb1, 0x00fbd3, 0x00fd3d, 0x00fd50, 0x00fd8f, 0x00fd92, 0x00fdc7, 0x00fdf0, 0x00fdfb, 0x00fe00, 0x00fe0f, 0x00fe20, 0x00fe2f, + 0x00fe33, 0x00fe34, 0x00fe4d, 0x00fe4f, 0x00fe70, 0x00fe74, 0x00fe76, 0x00fefc, 0x00ff10, 0x00ff19, 0x00ff21, 0x00ff3a, 0x00ff3f, 0x00ff3f, 0x00ff41, 0x00ff5a, 0x00ff66, + 0x00ffbe, 0x00ffc2, 0x00ffc7, 0x00ffca, 0x00ffcf, 0x00ffd2, 0x00ffd7, 0x00ffda, 0x00ffdc, 0x010000, 0x01000b, 0x01000d, 0x010026, 0x010028, 0x01003a, 0x01003c, 0x01003d, + 0x01003f, 0x01004d, 0x010050, 0x01005d, 0x010080, 0x0100fa, 0x010140, 0x010174, 0x0101fd, 0x0101fd, 0x010280, 0x01029c, 0x0102a0, 0x0102d0, 0x0102e0, 0x0102e0, 0x010300, + 0x01031f, 0x01032d, 0x01034a, 0x010350, 0x01037a, 0x010380, 0x01039d, 0x0103a0, 0x0103c3, 0x0103c8, 0x0103cf, 0x0103d1, 0x0103d5, 0x010400, 0x01049d, 0x0104a0, 0x0104a9, + 0x0104b0, 0x0104d3, 0x0104d8, 0x0104fb, 0x010500, 0x010527, 0x010530, 0x010563, 0x010570, 0x01057a, 0x01057c, 0x01058a, 0x01058c, 0x010592, 0x010594, 0x010595, 0x010597, + 0x0105a1, 0x0105a3, 0x0105b1, 0x0105b3, 0x0105b9, 0x0105bb, 0x0105bc, 0x010600, 0x010736, 0x010740, 0x010755, 0x010760, 0x010767, 0x010780, 0x010785, 0x010787, 0x0107b0, + 0x0107b2, 0x0107ba, 0x010800, 0x010805, 0x010808, 0x010808, 0x01080a, 0x010835, 0x010837, 0x010838, 0x01083c, 0x01083c, 0x01083f, 0x010855, 0x010860, 0x010876, 0x010880, + 0x01089e, 0x0108e0, 0x0108f2, 0x0108f4, 0x0108f5, 0x010900, 0x010915, 0x010920, 0x010939, 0x010980, 0x0109b7, 0x0109be, 0x0109bf, 0x010a00, 0x010a03, 0x010a05, 0x010a06, + 0x010a0c, 0x010a13, 0x010a15, 0x010a17, 0x010a19, 0x010a35, 0x010a38, 0x010a3a, 0x010a3f, 0x010a3f, 0x010a60, 0x010a7c, 0x010a80, 0x010a9c, 0x010ac0, 0x010ac7, 0x010ac9, + 0x010ae6, 0x010b00, 0x010b35, 0x010b40, 0x010b55, 0x010b60, 0x010b72, 0x010b80, 0x010b91, 0x010c00, 0x010c48, 0x010c80, 0x010cb2, 0x010cc0, 0x010cf2, 0x010d00, 0x010d27, + 0x010d30, 0x010d39, 0x010e80, 0x010ea9, 0x010eab, 0x010eac, 0x010eb0, 0x010eb1, 0x010f00, 0x010f1c, 0x010f27, 0x010f27, 0x010f30, 0x010f50, 0x010f70, 0x010f85, 0x010fb0, + 0x010fc4, 0x010fe0, 0x010ff6, 0x011000, 0x011046, 0x011066, 0x011075, 0x01107f, 0x0110ba, 0x0110c2, 0x0110c2, 0x0110d0, 0x0110e8, 0x0110f0, 0x0110f9, 0x011100, 0x011134, + 0x011136, 0x01113f, 0x011144, 0x011147, 0x011150, 0x011173, 0x011176, 0x011176, 0x011180, 0x0111c4, 0x0111c9, 0x0111cc, 0x0111ce, 0x0111da, 0x0111dc, 0x0111dc, 0x011200, + 0x011211, 0x011213, 0x011237, 0x01123e, 0x01123e, 0x011280, 0x011286, 0x011288, 0x011288, 0x01128a, 0x01128d, 0x01128f, 0x01129d, 0x01129f, 0x0112a8, 0x0112b0, 0x0112ea, + 0x0112f0, 0x0112f9, 0x011300, 0x011303, 0x011305, 0x01130c, 0x01130f, 0x011310, 0x011313, 0x011328, 0x01132a, 0x011330, 0x011332, 0x011333, 0x011335, 0x011339, 0x01133b, + 0x011344, 0x011347, 0x011348, 0x01134b, 0x01134d, 0x011350, 0x011350, 0x011357, 0x011357, 0x01135d, 0x011363, 0x011366, 0x01136c, 0x011370, 0x011374, 0x011400, 0x01144a, + 0x011450, 0x011459, 0x01145e, 0x011461, 0x011480, 0x0114c5, 0x0114c7, 0x0114c7, 0x0114d0, 0x0114d9, 0x011580, 0x0115b5, 0x0115b8, 0x0115c0, 0x0115d8, 0x0115dd, 0x011600, + 0x011640, 0x011644, 0x011644, 0x011650, 0x011659, 0x011680, 0x0116b8, 0x0116c0, 0x0116c9, 0x011700, 0x01171a, 0x01171d, 0x01172b, 0x011730, 0x011739, 0x011740, 0x011746, + 0x011800, 0x01183a, 0x0118a0, 0x0118e9, 0x0118ff, 0x011906, 0x011909, 0x011909, 0x01190c, 0x011913, 0x011915, 0x011916, 0x011918, 0x011935, 0x011937, 0x011938, 0x01193b, + 0x011943, 0x011950, 0x011959, 0x0119a0, 0x0119a7, 0x0119aa, 0x0119d7, 0x0119da, 0x0119e1, 0x0119e3, 0x0119e4, 0x011a00, 0x011a3e, 0x011a47, 0x011a47, 0x011a50, 0x011a99, + 0x011a9d, 0x011a9d, 0x011ab0, 0x011af8, 0x011c00, 0x011c08, 0x011c0a, 0x011c36, 0x011c38, 0x011c40, 0x011c50, 0x011c59, 0x011c72, 0x011c8f, 0x011c92, 0x011ca7, 0x011ca9, + 0x011cb6, 0x011d00, 0x011d06, 0x011d08, 0x011d09, 0x011d0b, 0x011d36, 0x011d3a, 0x011d3a, 0x011d3c, 0x011d3d, 0x011d3f, 0x011d47, 0x011d50, 0x011d59, 0x011d60, 0x011d65, + 0x011d67, 0x011d68, 0x011d6a, 0x011d8e, 0x011d90, 0x011d91, 0x011d93, 0x011d98, 0x011da0, 0x011da9, 0x011ee0, 0x011ef6, 0x011fb0, 0x011fb0, 0x012000, 0x012399, 0x012400, + 0x01246e, 0x012480, 0x012543, 0x012f90, 0x012ff0, 0x013000, 0x01342e, 0x014400, 0x014646, 0x016800, 0x016a38, 0x016a40, 0x016a5e, 0x016a60, 0x016a69, 0x016a70, 0x016abe, + 0x016ac0, 0x016ac9, 0x016ad0, 0x016aed, 0x016af0, 0x016af4, 0x016b00, 0x016b36, 0x016b40, 0x016b43, 0x016b50, 0x016b59, 0x016b63, 0x016b77, 0x016b7d, 0x016b8f, 0x016e40, + 0x016e7f, 0x016f00, 0x016f4a, 0x016f4f, 0x016f87, 0x016f8f, 0x016f9f, 0x016fe0, 0x016fe1, 0x016fe3, 0x016fe4, 0x016ff0, 0x016ff1, 0x017000, 0x0187f7, 0x018800, 0x018cd5, + 0x018d00, 0x018d08, 0x01aff0, 0x01aff3, 0x01aff5, 0x01affb, 0x01affd, 0x01affe, 0x01b000, 0x01b122, 0x01b150, 0x01b152, 0x01b164, 0x01b167, 0x01b170, 0x01b2fb, 0x01bc00, + 0x01bc6a, 0x01bc70, 0x01bc7c, 0x01bc80, 0x01bc88, 0x01bc90, 0x01bc99, 0x01bc9d, 0x01bc9e, 0x01cf00, 0x01cf2d, 0x01cf30, 0x01cf46, 0x01d165, 0x01d169, 0x01d16d, 0x01d172, + 0x01d17b, 0x01d182, 0x01d185, 0x01d18b, 0x01d1aa, 0x01d1ad, 0x01d242, 0x01d244, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, + 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, + 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d6c0, 0x01d6c2, 0x01d6da, 0x01d6dc, + 0x01d6fa, 0x01d6fc, 0x01d714, 0x01d716, 0x01d734, 0x01d736, 0x01d74e, 0x01d750, 0x01d76e, 0x01d770, 0x01d788, 0x01d78a, 0x01d7a8, 0x01d7aa, 0x01d7c2, 0x01d7c4, 0x01d7cb, + 0x01d7ce, 0x01d7ff, 0x01da00, 0x01da36, 0x01da3b, 0x01da6c, 0x01da75, 0x01da75, 0x01da84, 0x01da84, 0x01da9b, 0x01da9f, 0x01daa1, 0x01daaf, 0x01df00, 0x01df1e, 0x01e000, + 0x01e006, 0x01e008, 0x01e018, 0x01e01b, 0x01e021, 0x01e023, 0x01e024, 0x01e026, 0x01e02a, 0x01e100, 0x01e12c, 0x01e130, 0x01e13d, 0x01e140, 0x01e149, 0x01e14e, 0x01e14e, + 0x01e290, 0x01e2ae, 0x01e2c0, 0x01e2f9, 0x01e7e0, 0x01e7e6, 0x01e7e8, 0x01e7eb, 0x01e7ed, 0x01e7ee, 0x01e7f0, 0x01e7fe, 0x01e800, 0x01e8c4, 0x01e8d0, 0x01e8d6, 0x01e900, + 0x01e94b, 0x01e950, 0x01e959, 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, 0x01ee37, + 0x01ee39, 0x01ee39, 0x01ee3b, 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, + 0x01ee54, 0x01ee57, 0x01ee57, 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, + 0x01ee6c, 0x01ee72, 0x01ee74, 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, 0x01ee80, 0x01ee89, 0x01ee8b, 0x01ee9b, 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, + 0x01eebb, 0x01fbf0, 0x01fbf9, 0x020000, 0x02a6df, 0x02a700, 0x02b738, 0x02b740, 0x02b81d, 0x02b820, 0x02cea1, 0x02ceb0, 0x02ebe0, 0x02f800, 0x02fa1d, 0x030000, 0x03134a, + 0x0e0100, 0x0e01ef)); } private static void populateIDS() { @@ -2021,38 +2064,38 @@ private static void populateIDS() { 0x00037f, 0x000386, 0x000386, 0x000388, 0x00038a, 0x00038c, 0x00038c, 0x00038e, 0x0003a1, 0x0003a3, 0x0003f5, 0x0003f7, 0x000481, 0x00048a, 0x00052f, 0x000531, 0x000556, 0x000559, 0x000559, 0x000560, 0x000588, 0x0005d0, 0x0005ea, 0x0005ef, 0x0005f2, 0x000620, 0x00064a, 0x00066e, 0x00066f, 0x000671, 0x0006d3, 0x0006d5, 0x0006d5, 0x0006e5, 0x0006e6, 0x0006ee, 0x0006ef, 0x0006fa, 0x0006fc, 0x0006ff, 0x0006ff, 0x000710, 0x000710, 0x000712, 0x00072f, 0x00074d, 0x0007a5, 0x0007b1, 0x0007b1, 0x0007ca, 0x0007ea, - 0x0007f4, 0x0007f5, 0x0007fa, 0x0007fa, 0x000800, 0x000815, 0x00081a, 0x00081a, 0x000824, 0x000824, 0x000828, 0x000828, 0x000840, 0x000858, 0x000860, 0x00086a, 0x0008a0, - 0x0008b4, 0x0008b6, 0x0008c7, 0x000904, 0x000939, 0x00093d, 0x00093d, 0x000950, 0x000950, 0x000958, 0x000961, 0x000971, 0x000980, 0x000985, 0x00098c, 0x00098f, 0x000990, - 0x000993, 0x0009a8, 0x0009aa, 0x0009b0, 0x0009b2, 0x0009b2, 0x0009b6, 0x0009b9, 0x0009bd, 0x0009bd, 0x0009ce, 0x0009ce, 0x0009dc, 0x0009dd, 0x0009df, 0x0009e1, 0x0009f0, - 0x0009f1, 0x0009fc, 0x0009fc, 0x000a05, 0x000a0a, 0x000a0f, 0x000a10, 0x000a13, 0x000a28, 0x000a2a, 0x000a30, 0x000a32, 0x000a33, 0x000a35, 0x000a36, 0x000a38, 0x000a39, - 0x000a59, 0x000a5c, 0x000a5e, 0x000a5e, 0x000a72, 0x000a74, 0x000a85, 0x000a8d, 0x000a8f, 0x000a91, 0x000a93, 0x000aa8, 0x000aaa, 0x000ab0, 0x000ab2, 0x000ab3, 0x000ab5, - 0x000ab9, 0x000abd, 0x000abd, 0x000ad0, 0x000ad0, 0x000ae0, 0x000ae1, 0x000af9, 0x000af9, 0x000b05, 0x000b0c, 0x000b0f, 0x000b10, 0x000b13, 0x000b28, 0x000b2a, 0x000b30, - 0x000b32, 0x000b33, 0x000b35, 0x000b39, 0x000b3d, 0x000b3d, 0x000b5c, 0x000b5d, 0x000b5f, 0x000b61, 0x000b71, 0x000b71, 0x000b83, 0x000b83, 0x000b85, 0x000b8a, 0x000b8e, - 0x000b90, 0x000b92, 0x000b95, 0x000b99, 0x000b9a, 0x000b9c, 0x000b9c, 0x000b9e, 0x000b9f, 0x000ba3, 0x000ba4, 0x000ba8, 0x000baa, 0x000bae, 0x000bb9, 0x000bd0, 0x000bd0, - 0x000c05, 0x000c0c, 0x000c0e, 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3d, 0x000c3d, 0x000c58, 0x000c5a, 0x000c60, 0x000c61, 0x000c80, 0x000c80, 0x000c85, - 0x000c8c, 0x000c8e, 0x000c90, 0x000c92, 0x000ca8, 0x000caa, 0x000cb3, 0x000cb5, 0x000cb9, 0x000cbd, 0x000cbd, 0x000cde, 0x000cde, 0x000ce0, 0x000ce1, 0x000cf1, 0x000cf2, - 0x000d04, 0x000d0c, 0x000d0e, 0x000d10, 0x000d12, 0x000d3a, 0x000d3d, 0x000d3d, 0x000d4e, 0x000d4e, 0x000d54, 0x000d56, 0x000d5f, 0x000d61, 0x000d7a, 0x000d7f, 0x000d85, - 0x000d96, 0x000d9a, 0x000db1, 0x000db3, 0x000dbb, 0x000dbd, 0x000dbd, 0x000dc0, 0x000dc6, 0x000e01, 0x000e30, 0x000e32, 0x000e33, 0x000e40, 0x000e46, 0x000e81, 0x000e82, - 0x000e84, 0x000e84, 0x000e86, 0x000e8a, 0x000e8c, 0x000ea3, 0x000ea5, 0x000ea5, 0x000ea7, 0x000eb0, 0x000eb2, 0x000eb3, 0x000ebd, 0x000ebd, 0x000ec0, 0x000ec4, 0x000ec6, - 0x000ec6, 0x000edc, 0x000edf, 0x000f00, 0x000f00, 0x000f40, 0x000f47, 0x000f49, 0x000f6c, 0x000f88, 0x000f8c, 0x001000, 0x00102a, 0x00103f, 0x00103f, 0x001050, 0x001055, - 0x00105a, 0x00105d, 0x001061, 0x001061, 0x001065, 0x001066, 0x00106e, 0x001070, 0x001075, 0x001081, 0x00108e, 0x00108e, 0x0010a0, 0x0010c5, 0x0010c7, 0x0010c7, 0x0010cd, - 0x0010cd, 0x0010d0, 0x0010fa, 0x0010fc, 0x001248, 0x00124a, 0x00124d, 0x001250, 0x001256, 0x001258, 0x001258, 0x00125a, 0x00125d, 0x001260, 0x001288, 0x00128a, 0x00128d, - 0x001290, 0x0012b0, 0x0012b2, 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, 0x0012d8, 0x001310, 0x001312, 0x001315, 0x001318, - 0x00135a, 0x001380, 0x00138f, 0x0013a0, 0x0013f5, 0x0013f8, 0x0013fd, 0x001401, 0x00166c, 0x00166f, 0x00167f, 0x001681, 0x00169a, 0x0016a0, 0x0016ea, 0x0016ee, 0x0016f8, - 0x001700, 0x00170c, 0x00170e, 0x001711, 0x001720, 0x001731, 0x001740, 0x001751, 0x001760, 0x00176c, 0x00176e, 0x001770, 0x001780, 0x0017b3, 0x0017d7, 0x0017d7, 0x0017dc, - 0x0017dc, 0x001820, 0x001878, 0x001880, 0x0018a8, 0x0018aa, 0x0018aa, 0x0018b0, 0x0018f5, 0x001900, 0x00191e, 0x001950, 0x00196d, 0x001970, 0x001974, 0x001980, 0x0019ab, - 0x0019b0, 0x0019c9, 0x001a00, 0x001a16, 0x001a20, 0x001a54, 0x001aa7, 0x001aa7, 0x001b05, 0x001b33, 0x001b45, 0x001b4b, 0x001b83, 0x001ba0, 0x001bae, 0x001baf, 0x001bba, - 0x001be5, 0x001c00, 0x001c23, 0x001c4d, 0x001c4f, 0x001c5a, 0x001c7d, 0x001c80, 0x001c88, 0x001c90, 0x001cba, 0x001cbd, 0x001cbf, 0x001ce9, 0x001cec, 0x001cee, 0x001cf3, - 0x001cf5, 0x001cf6, 0x001cfa, 0x001cfa, 0x001d00, 0x001dbf, 0x001e00, 0x001f15, 0x001f18, 0x001f1d, 0x001f20, 0x001f45, 0x001f48, 0x001f4d, 0x001f50, 0x001f57, 0x001f59, - 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f7d, 0x001f80, 0x001fb4, 0x001fb6, 0x001fbc, 0x001fbe, 0x001fbe, 0x001fc2, 0x001fc4, 0x001fc6, 0x001fcc, - 0x001fd0, 0x001fd3, 0x001fd6, 0x001fdb, 0x001fe0, 0x001fec, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ffc, 0x002071, 0x002071, 0x00207f, 0x00207f, 0x002090, 0x00209c, 0x002102, - 0x002102, 0x002107, 0x002107, 0x00210a, 0x002113, 0x002115, 0x002115, 0x002118, 0x00211d, 0x002124, 0x002124, 0x002126, 0x002126, 0x002128, 0x002128, 0x00212a, 0x002139, - 0x00213c, 0x00213f, 0x002145, 0x002149, 0x00214e, 0x00214e, 0x002160, 0x002188, 0x002c00, 0x002c2e, 0x002c30, 0x002c5e, 0x002c60, 0x002ce4, 0x002ceb, 0x002cee, 0x002cf2, - 0x002cf3, 0x002d00, 0x002d25, 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, 0x002d30, 0x002d67, 0x002d6f, 0x002d6f, 0x002d80, 0x002d96, 0x002da0, 0x002da6, 0x002da8, 0x002dae, - 0x002db0, 0x002db6, 0x002db8, 0x002dbe, 0x002dc0, 0x002dc6, 0x002dc8, 0x002dce, 0x002dd0, 0x002dd6, 0x002dd8, 0x002dde, 0x003005, 0x003007, 0x003021, 0x003029, 0x003031, - 0x003035, 0x003038, 0x00303c, 0x003041, 0x003096, 0x00309b, 0x00309f, 0x0030a1, 0x0030fa, 0x0030fc, 0x0030ff, 0x003105, 0x00312f, 0x003131, 0x00318e, 0x0031a0, 0x0031bf, - 0x0031f0, 0x0031ff, 0x003400, 0x004dbf, 0x004e00, 0x009ffc, 0x00a000, 0x00a48c, 0x00a4d0, 0x00a4fd, 0x00a500, 0x00a60c, 0x00a610, 0x00a61f, 0x00a62a, 0x00a62b, 0x00a640, - 0x00a66e, 0x00a67f, 0x00a69d, 0x00a6a0, 0x00a6ef, 0x00a717, 0x00a71f, 0x00a722, 0x00a788, 0x00a78b, 0x00a7bf, 0x00a7c2, 0x00a7ca, 0x00a7f5, 0x00a801, 0x00a803, 0x00a805, + 0x0007f4, 0x0007f5, 0x0007fa, 0x0007fa, 0x000800, 0x000815, 0x00081a, 0x00081a, 0x000824, 0x000824, 0x000828, 0x000828, 0x000840, 0x000858, 0x000860, 0x00086a, 0x000870, + 0x000887, 0x000889, 0x00088e, 0x0008a0, 0x0008c9, 0x000904, 0x000939, 0x00093d, 0x00093d, 0x000950, 0x000950, 0x000958, 0x000961, 0x000971, 0x000980, 0x000985, 0x00098c, + 0x00098f, 0x000990, 0x000993, 0x0009a8, 0x0009aa, 0x0009b0, 0x0009b2, 0x0009b2, 0x0009b6, 0x0009b9, 0x0009bd, 0x0009bd, 0x0009ce, 0x0009ce, 0x0009dc, 0x0009dd, 0x0009df, + 0x0009e1, 0x0009f0, 0x0009f1, 0x0009fc, 0x0009fc, 0x000a05, 0x000a0a, 0x000a0f, 0x000a10, 0x000a13, 0x000a28, 0x000a2a, 0x000a30, 0x000a32, 0x000a33, 0x000a35, 0x000a36, + 0x000a38, 0x000a39, 0x000a59, 0x000a5c, 0x000a5e, 0x000a5e, 0x000a72, 0x000a74, 0x000a85, 0x000a8d, 0x000a8f, 0x000a91, 0x000a93, 0x000aa8, 0x000aaa, 0x000ab0, 0x000ab2, + 0x000ab3, 0x000ab5, 0x000ab9, 0x000abd, 0x000abd, 0x000ad0, 0x000ad0, 0x000ae0, 0x000ae1, 0x000af9, 0x000af9, 0x000b05, 0x000b0c, 0x000b0f, 0x000b10, 0x000b13, 0x000b28, + 0x000b2a, 0x000b30, 0x000b32, 0x000b33, 0x000b35, 0x000b39, 0x000b3d, 0x000b3d, 0x000b5c, 0x000b5d, 0x000b5f, 0x000b61, 0x000b71, 0x000b71, 0x000b83, 0x000b83, 0x000b85, + 0x000b8a, 0x000b8e, 0x000b90, 0x000b92, 0x000b95, 0x000b99, 0x000b9a, 0x000b9c, 0x000b9c, 0x000b9e, 0x000b9f, 0x000ba3, 0x000ba4, 0x000ba8, 0x000baa, 0x000bae, 0x000bb9, + 0x000bd0, 0x000bd0, 0x000c05, 0x000c0c, 0x000c0e, 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3d, 0x000c3d, 0x000c58, 0x000c5a, 0x000c5d, 0x000c5d, 0x000c60, + 0x000c61, 0x000c80, 0x000c80, 0x000c85, 0x000c8c, 0x000c8e, 0x000c90, 0x000c92, 0x000ca8, 0x000caa, 0x000cb3, 0x000cb5, 0x000cb9, 0x000cbd, 0x000cbd, 0x000cdd, 0x000cde, + 0x000ce0, 0x000ce1, 0x000cf1, 0x000cf2, 0x000d04, 0x000d0c, 0x000d0e, 0x000d10, 0x000d12, 0x000d3a, 0x000d3d, 0x000d3d, 0x000d4e, 0x000d4e, 0x000d54, 0x000d56, 0x000d5f, + 0x000d61, 0x000d7a, 0x000d7f, 0x000d85, 0x000d96, 0x000d9a, 0x000db1, 0x000db3, 0x000dbb, 0x000dbd, 0x000dbd, 0x000dc0, 0x000dc6, 0x000e01, 0x000e30, 0x000e32, 0x000e33, + 0x000e40, 0x000e46, 0x000e81, 0x000e82, 0x000e84, 0x000e84, 0x000e86, 0x000e8a, 0x000e8c, 0x000ea3, 0x000ea5, 0x000ea5, 0x000ea7, 0x000eb0, 0x000eb2, 0x000eb3, 0x000ebd, + 0x000ebd, 0x000ec0, 0x000ec4, 0x000ec6, 0x000ec6, 0x000edc, 0x000edf, 0x000f00, 0x000f00, 0x000f40, 0x000f47, 0x000f49, 0x000f6c, 0x000f88, 0x000f8c, 0x001000, 0x00102a, + 0x00103f, 0x00103f, 0x001050, 0x001055, 0x00105a, 0x00105d, 0x001061, 0x001061, 0x001065, 0x001066, 0x00106e, 0x001070, 0x001075, 0x001081, 0x00108e, 0x00108e, 0x0010a0, + 0x0010c5, 0x0010c7, 0x0010c7, 0x0010cd, 0x0010cd, 0x0010d0, 0x0010fa, 0x0010fc, 0x001248, 0x00124a, 0x00124d, 0x001250, 0x001256, 0x001258, 0x001258, 0x00125a, 0x00125d, + 0x001260, 0x001288, 0x00128a, 0x00128d, 0x001290, 0x0012b0, 0x0012b2, 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, 0x0012d8, + 0x001310, 0x001312, 0x001315, 0x001318, 0x00135a, 0x001380, 0x00138f, 0x0013a0, 0x0013f5, 0x0013f8, 0x0013fd, 0x001401, 0x00166c, 0x00166f, 0x00167f, 0x001681, 0x00169a, + 0x0016a0, 0x0016ea, 0x0016ee, 0x0016f8, 0x001700, 0x001711, 0x00171f, 0x001731, 0x001740, 0x001751, 0x001760, 0x00176c, 0x00176e, 0x001770, 0x001780, 0x0017b3, 0x0017d7, + 0x0017d7, 0x0017dc, 0x0017dc, 0x001820, 0x001878, 0x001880, 0x0018a8, 0x0018aa, 0x0018aa, 0x0018b0, 0x0018f5, 0x001900, 0x00191e, 0x001950, 0x00196d, 0x001970, 0x001974, + 0x001980, 0x0019ab, 0x0019b0, 0x0019c9, 0x001a00, 0x001a16, 0x001a20, 0x001a54, 0x001aa7, 0x001aa7, 0x001b05, 0x001b33, 0x001b45, 0x001b4c, 0x001b83, 0x001ba0, 0x001bae, + 0x001baf, 0x001bba, 0x001be5, 0x001c00, 0x001c23, 0x001c4d, 0x001c4f, 0x001c5a, 0x001c7d, 0x001c80, 0x001c88, 0x001c90, 0x001cba, 0x001cbd, 0x001cbf, 0x001ce9, 0x001cec, + 0x001cee, 0x001cf3, 0x001cf5, 0x001cf6, 0x001cfa, 0x001cfa, 0x001d00, 0x001dbf, 0x001e00, 0x001f15, 0x001f18, 0x001f1d, 0x001f20, 0x001f45, 0x001f48, 0x001f4d, 0x001f50, + 0x001f57, 0x001f59, 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f7d, 0x001f80, 0x001fb4, 0x001fb6, 0x001fbc, 0x001fbe, 0x001fbe, 0x001fc2, 0x001fc4, + 0x001fc6, 0x001fcc, 0x001fd0, 0x001fd3, 0x001fd6, 0x001fdb, 0x001fe0, 0x001fec, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ffc, 0x002071, 0x002071, 0x00207f, 0x00207f, 0x002090, + 0x00209c, 0x002102, 0x002102, 0x002107, 0x002107, 0x00210a, 0x002113, 0x002115, 0x002115, 0x002118, 0x00211d, 0x002124, 0x002124, 0x002126, 0x002126, 0x002128, 0x002128, + 0x00212a, 0x002139, 0x00213c, 0x00213f, 0x002145, 0x002149, 0x00214e, 0x00214e, 0x002160, 0x002188, 0x002c00, 0x002ce4, 0x002ceb, 0x002cee, 0x002cf2, 0x002cf3, 0x002d00, + 0x002d25, 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, 0x002d30, 0x002d67, 0x002d6f, 0x002d6f, 0x002d80, 0x002d96, 0x002da0, 0x002da6, 0x002da8, 0x002dae, 0x002db0, 0x002db6, + 0x002db8, 0x002dbe, 0x002dc0, 0x002dc6, 0x002dc8, 0x002dce, 0x002dd0, 0x002dd6, 0x002dd8, 0x002dde, 0x003005, 0x003007, 0x003021, 0x003029, 0x003031, 0x003035, 0x003038, + 0x00303c, 0x003041, 0x003096, 0x00309b, 0x00309f, 0x0030a1, 0x0030fa, 0x0030fc, 0x0030ff, 0x003105, 0x00312f, 0x003131, 0x00318e, 0x0031a0, 0x0031bf, 0x0031f0, 0x0031ff, + 0x003400, 0x004dbf, 0x004e00, 0x00a48c, 0x00a4d0, 0x00a4fd, 0x00a500, 0x00a60c, 0x00a610, 0x00a61f, 0x00a62a, 0x00a62b, 0x00a640, 0x00a66e, 0x00a67f, 0x00a69d, 0x00a6a0, + 0x00a6ef, 0x00a717, 0x00a71f, 0x00a722, 0x00a788, 0x00a78b, 0x00a7ca, 0x00a7d0, 0x00a7d1, 0x00a7d3, 0x00a7d3, 0x00a7d5, 0x00a7d9, 0x00a7f2, 0x00a801, 0x00a803, 0x00a805, 0x00a807, 0x00a80a, 0x00a80c, 0x00a822, 0x00a840, 0x00a873, 0x00a882, 0x00a8b3, 0x00a8f2, 0x00a8f7, 0x00a8fb, 0x00a8fb, 0x00a8fd, 0x00a8fe, 0x00a90a, 0x00a925, 0x00a930, 0x00a946, 0x00a960, 0x00a97c, 0x00a984, 0x00a9b2, 0x00a9cf, 0x00a9cf, 0x00a9e0, 0x00a9e4, 0x00a9e6, 0x00a9ef, 0x00a9fa, 0x00a9fe, 0x00aa00, 0x00aa28, 0x00aa40, 0x00aa42, 0x00aa44, 0x00aa4b, 0x00aa60, 0x00aa76, 0x00aa7a, 0x00aa7a, 0x00aa7e, 0x00aaaf, 0x00aab1, 0x00aab1, 0x00aab5, 0x00aab6, 0x00aab9, 0x00aabd, 0x00aac0, 0x00aac0, 0x00aac2, @@ -2063,33 +2106,36 @@ private static void populateIDS() { 0x00ff5a, 0x00ff66, 0x00ffbe, 0x00ffc2, 0x00ffc7, 0x00ffca, 0x00ffcf, 0x00ffd2, 0x00ffd7, 0x00ffda, 0x00ffdc, 0x010000, 0x01000b, 0x01000d, 0x010026, 0x010028, 0x01003a, 0x01003c, 0x01003d, 0x01003f, 0x01004d, 0x010050, 0x01005d, 0x010080, 0x0100fa, 0x010140, 0x010174, 0x010280, 0x01029c, 0x0102a0, 0x0102d0, 0x010300, 0x01031f, 0x01032d, 0x01034a, 0x010350, 0x010375, 0x010380, 0x01039d, 0x0103a0, 0x0103c3, 0x0103c8, 0x0103cf, 0x0103d1, 0x0103d5, 0x010400, 0x01049d, 0x0104b0, 0x0104d3, 0x0104d8, 0x0104fb, - 0x010500, 0x010527, 0x010530, 0x010563, 0x010600, 0x010736, 0x010740, 0x010755, 0x010760, 0x010767, 0x010800, 0x010805, 0x010808, 0x010808, 0x01080a, 0x010835, 0x010837, - 0x010838, 0x01083c, 0x01083c, 0x01083f, 0x010855, 0x010860, 0x010876, 0x010880, 0x01089e, 0x0108e0, 0x0108f2, 0x0108f4, 0x0108f5, 0x010900, 0x010915, 0x010920, 0x010939, - 0x010980, 0x0109b7, 0x0109be, 0x0109bf, 0x010a00, 0x010a00, 0x010a10, 0x010a13, 0x010a15, 0x010a17, 0x010a19, 0x010a35, 0x010a60, 0x010a7c, 0x010a80, 0x010a9c, 0x010ac0, - 0x010ac7, 0x010ac9, 0x010ae4, 0x010b00, 0x010b35, 0x010b40, 0x010b55, 0x010b60, 0x010b72, 0x010b80, 0x010b91, 0x010c00, 0x010c48, 0x010c80, 0x010cb2, 0x010cc0, 0x010cf2, - 0x010d00, 0x010d23, 0x010e80, 0x010ea9, 0x010eb0, 0x010eb1, 0x010f00, 0x010f1c, 0x010f27, 0x010f27, 0x010f30, 0x010f45, 0x010fb0, 0x010fc4, 0x010fe0, 0x010ff6, 0x011003, - 0x011037, 0x011083, 0x0110af, 0x0110d0, 0x0110e8, 0x011103, 0x011126, 0x011144, 0x011144, 0x011147, 0x011147, 0x011150, 0x011172, 0x011176, 0x011176, 0x011183, 0x0111b2, - 0x0111c1, 0x0111c4, 0x0111da, 0x0111da, 0x0111dc, 0x0111dc, 0x011200, 0x011211, 0x011213, 0x01122b, 0x011280, 0x011286, 0x011288, 0x011288, 0x01128a, 0x01128d, 0x01128f, - 0x01129d, 0x01129f, 0x0112a8, 0x0112b0, 0x0112de, 0x011305, 0x01130c, 0x01130f, 0x011310, 0x011313, 0x011328, 0x01132a, 0x011330, 0x011332, 0x011333, 0x011335, 0x011339, - 0x01133d, 0x01133d, 0x011350, 0x011350, 0x01135d, 0x011361, 0x011400, 0x011434, 0x011447, 0x01144a, 0x01145f, 0x011461, 0x011480, 0x0114af, 0x0114c4, 0x0114c5, 0x0114c7, - 0x0114c7, 0x011580, 0x0115ae, 0x0115d8, 0x0115db, 0x011600, 0x01162f, 0x011644, 0x011644, 0x011680, 0x0116aa, 0x0116b8, 0x0116b8, 0x011700, 0x01171a, 0x011800, 0x01182b, - 0x0118a0, 0x0118df, 0x0118ff, 0x011906, 0x011909, 0x011909, 0x01190c, 0x011913, 0x011915, 0x011916, 0x011918, 0x01192f, 0x01193f, 0x01193f, 0x011941, 0x011941, 0x0119a0, - 0x0119a7, 0x0119aa, 0x0119d0, 0x0119e1, 0x0119e1, 0x0119e3, 0x0119e3, 0x011a00, 0x011a00, 0x011a0b, 0x011a32, 0x011a3a, 0x011a3a, 0x011a50, 0x011a50, 0x011a5c, 0x011a89, - 0x011a9d, 0x011a9d, 0x011ac0, 0x011af8, 0x011c00, 0x011c08, 0x011c0a, 0x011c2e, 0x011c40, 0x011c40, 0x011c72, 0x011c8f, 0x011d00, 0x011d06, 0x011d08, 0x011d09, 0x011d0b, - 0x011d30, 0x011d46, 0x011d46, 0x011d60, 0x011d65, 0x011d67, 0x011d68, 0x011d6a, 0x011d89, 0x011d98, 0x011d98, 0x011ee0, 0x011ef2, 0x011fb0, 0x011fb0, 0x012000, 0x012399, - 0x012400, 0x01246e, 0x012480, 0x012543, 0x013000, 0x01342e, 0x014400, 0x014646, 0x016800, 0x016a38, 0x016a40, 0x016a5e, 0x016ad0, 0x016aed, 0x016b00, 0x016b2f, 0x016b40, + 0x010500, 0x010527, 0x010530, 0x010563, 0x010570, 0x01057a, 0x01057c, 0x01058a, 0x01058c, 0x010592, 0x010594, 0x010595, 0x010597, 0x0105a1, 0x0105a3, 0x0105b1, 0x0105b3, + 0x0105b9, 0x0105bb, 0x0105bc, 0x010600, 0x010736, 0x010740, 0x010755, 0x010760, 0x010767, 0x010780, 0x010785, 0x010787, 0x0107b0, 0x0107b2, 0x0107ba, 0x010800, 0x010805, + 0x010808, 0x010808, 0x01080a, 0x010835, 0x010837, 0x010838, 0x01083c, 0x01083c, 0x01083f, 0x010855, 0x010860, 0x010876, 0x010880, 0x01089e, 0x0108e0, 0x0108f2, 0x0108f4, + 0x0108f5, 0x010900, 0x010915, 0x010920, 0x010939, 0x010980, 0x0109b7, 0x0109be, 0x0109bf, 0x010a00, 0x010a00, 0x010a10, 0x010a13, 0x010a15, 0x010a17, 0x010a19, 0x010a35, + 0x010a60, 0x010a7c, 0x010a80, 0x010a9c, 0x010ac0, 0x010ac7, 0x010ac9, 0x010ae4, 0x010b00, 0x010b35, 0x010b40, 0x010b55, 0x010b60, 0x010b72, 0x010b80, 0x010b91, 0x010c00, + 0x010c48, 0x010c80, 0x010cb2, 0x010cc0, 0x010cf2, 0x010d00, 0x010d23, 0x010e80, 0x010ea9, 0x010eb0, 0x010eb1, 0x010f00, 0x010f1c, 0x010f27, 0x010f27, 0x010f30, 0x010f45, + 0x010f70, 0x010f81, 0x010fb0, 0x010fc4, 0x010fe0, 0x010ff6, 0x011003, 0x011037, 0x011071, 0x011072, 0x011075, 0x011075, 0x011083, 0x0110af, 0x0110d0, 0x0110e8, 0x011103, + 0x011126, 0x011144, 0x011144, 0x011147, 0x011147, 0x011150, 0x011172, 0x011176, 0x011176, 0x011183, 0x0111b2, 0x0111c1, 0x0111c4, 0x0111da, 0x0111da, 0x0111dc, 0x0111dc, + 0x011200, 0x011211, 0x011213, 0x01122b, 0x011280, 0x011286, 0x011288, 0x011288, 0x01128a, 0x01128d, 0x01128f, 0x01129d, 0x01129f, 0x0112a8, 0x0112b0, 0x0112de, 0x011305, + 0x01130c, 0x01130f, 0x011310, 0x011313, 0x011328, 0x01132a, 0x011330, 0x011332, 0x011333, 0x011335, 0x011339, 0x01133d, 0x01133d, 0x011350, 0x011350, 0x01135d, 0x011361, + 0x011400, 0x011434, 0x011447, 0x01144a, 0x01145f, 0x011461, 0x011480, 0x0114af, 0x0114c4, 0x0114c5, 0x0114c7, 0x0114c7, 0x011580, 0x0115ae, 0x0115d8, 0x0115db, 0x011600, + 0x01162f, 0x011644, 0x011644, 0x011680, 0x0116aa, 0x0116b8, 0x0116b8, 0x011700, 0x01171a, 0x011740, 0x011746, 0x011800, 0x01182b, 0x0118a0, 0x0118df, 0x0118ff, 0x011906, + 0x011909, 0x011909, 0x01190c, 0x011913, 0x011915, 0x011916, 0x011918, 0x01192f, 0x01193f, 0x01193f, 0x011941, 0x011941, 0x0119a0, 0x0119a7, 0x0119aa, 0x0119d0, 0x0119e1, + 0x0119e1, 0x0119e3, 0x0119e3, 0x011a00, 0x011a00, 0x011a0b, 0x011a32, 0x011a3a, 0x011a3a, 0x011a50, 0x011a50, 0x011a5c, 0x011a89, 0x011a9d, 0x011a9d, 0x011ab0, 0x011af8, + 0x011c00, 0x011c08, 0x011c0a, 0x011c2e, 0x011c40, 0x011c40, 0x011c72, 0x011c8f, 0x011d00, 0x011d06, 0x011d08, 0x011d09, 0x011d0b, 0x011d30, 0x011d46, 0x011d46, 0x011d60, + 0x011d65, 0x011d67, 0x011d68, 0x011d6a, 0x011d89, 0x011d98, 0x011d98, 0x011ee0, 0x011ef2, 0x011fb0, 0x011fb0, 0x012000, 0x012399, 0x012400, 0x01246e, 0x012480, 0x012543, + 0x012f90, 0x012ff0, 0x013000, 0x01342e, 0x014400, 0x014646, 0x016800, 0x016a38, 0x016a40, 0x016a5e, 0x016a70, 0x016abe, 0x016ad0, 0x016aed, 0x016b00, 0x016b2f, 0x016b40, 0x016b43, 0x016b63, 0x016b77, 0x016b7d, 0x016b8f, 0x016e40, 0x016e7f, 0x016f00, 0x016f4a, 0x016f50, 0x016f50, 0x016f93, 0x016f9f, 0x016fe0, 0x016fe1, 0x016fe3, 0x016fe3, - 0x017000, 0x0187f7, 0x018800, 0x018cd5, 0x018d00, 0x018d08, 0x01b000, 0x01b11e, 0x01b150, 0x01b152, 0x01b164, 0x01b167, 0x01b170, 0x01b2fb, 0x01bc00, 0x01bc6a, 0x01bc70, - 0x01bc7c, 0x01bc80, 0x01bc88, 0x01bc90, 0x01bc99, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, - 0x01d4ae, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, - 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d6c0, 0x01d6c2, 0x01d6da, 0x01d6dc, 0x01d6fa, 0x01d6fc, 0x01d714, - 0x01d716, 0x01d734, 0x01d736, 0x01d74e, 0x01d750, 0x01d76e, 0x01d770, 0x01d788, 0x01d78a, 0x01d7a8, 0x01d7aa, 0x01d7c2, 0x01d7c4, 0x01d7cb, 0x01e100, 0x01e12c, 0x01e137, - 0x01e13d, 0x01e14e, 0x01e14e, 0x01e2c0, 0x01e2eb, 0x01e800, 0x01e8c4, 0x01e900, 0x01e943, 0x01e94b, 0x01e94b, 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, - 0x01ee24, 0x01ee24, 0x01ee27, 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, 0x01ee39, 0x01ee3b, 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, - 0x01ee49, 0x01ee4b, 0x01ee4b, 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, 0x01ee57, 0x01ee57, 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, - 0x01ee5f, 0x01ee5f, 0x01ee61, 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, 0x01ee72, 0x01ee74, 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, 0x01ee80, - 0x01ee89, 0x01ee8b, 0x01ee9b, 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, 0x020000, 0x02a6dd, 0x02a700, 0x02b734, 0x02b740, 0x02b81d, 0x02b820, 0x02cea1, - 0x02ceb0, 0x02ebe0, 0x02f800, 0x02fa1d, 0x030000, 0x03134a)); + 0x017000, 0x0187f7, 0x018800, 0x018cd5, 0x018d00, 0x018d08, 0x01aff0, 0x01aff3, 0x01aff5, 0x01affb, 0x01affd, 0x01affe, 0x01b000, 0x01b122, 0x01b150, 0x01b152, 0x01b164, + 0x01b167, 0x01b170, 0x01b2fb, 0x01bc00, 0x01bc6a, 0x01bc70, 0x01bc7c, 0x01bc80, 0x01bc88, 0x01bc90, 0x01bc99, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, + 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, + 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d6c0, + 0x01d6c2, 0x01d6da, 0x01d6dc, 0x01d6fa, 0x01d6fc, 0x01d714, 0x01d716, 0x01d734, 0x01d736, 0x01d74e, 0x01d750, 0x01d76e, 0x01d770, 0x01d788, 0x01d78a, 0x01d7a8, 0x01d7aa, + 0x01d7c2, 0x01d7c4, 0x01d7cb, 0x01df00, 0x01df1e, 0x01e100, 0x01e12c, 0x01e137, 0x01e13d, 0x01e14e, 0x01e14e, 0x01e290, 0x01e2ad, 0x01e2c0, 0x01e2eb, 0x01e7e0, 0x01e7e6, + 0x01e7e8, 0x01e7eb, 0x01e7ed, 0x01e7ee, 0x01e7f0, 0x01e7fe, 0x01e800, 0x01e8c4, 0x01e900, 0x01e943, 0x01e94b, 0x01e94b, 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, + 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, 0x01ee39, 0x01ee3b, 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, + 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, 0x01ee57, 0x01ee57, 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, + 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, 0x01ee72, 0x01ee74, 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, + 0x01ee80, 0x01ee89, 0x01ee8b, 0x01ee9b, 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, 0x020000, 0x02a6df, 0x02a700, 0x02b738, 0x02b740, 0x02b81d, 0x02b820, + 0x02cea1, 0x02ceb0, 0x02ebe0, 0x02f800, 0x02fa1d, 0x030000, 0x03134a)); } private static void populateIDSB() { @@ -2102,8 +2148,8 @@ private static void populateIDST() { private static void populateIDEO() { SET_ENCODINGS.put("Ideo", - CodePointSet.createNoDedup(0x003006, 0x003007, 0x003021, 0x003029, 0x003038, 0x00303a, 0x003400, 0x004dbf, 0x004e00, 0x009ffc, 0x00f900, 0x00fa6d, 0x00fa70, 0x00fad9, 0x016fe4, - 0x016fe4, 0x017000, 0x0187f7, 0x018800, 0x018cd5, 0x018d00, 0x018d08, 0x01b170, 0x01b2fb, 0x020000, 0x02a6dd, 0x02a700, 0x02b734, 0x02b740, 0x02b81d, 0x02b820, + CodePointSet.createNoDedup(0x003006, 0x003007, 0x003021, 0x003029, 0x003038, 0x00303a, 0x003400, 0x004dbf, 0x004e00, 0x009fff, 0x00f900, 0x00fa6d, 0x00fa70, 0x00fad9, 0x016fe4, + 0x016fe4, 0x017000, 0x0187f7, 0x018800, 0x018cd5, 0x018d00, 0x018d08, 0x01b170, 0x01b2fb, 0x020000, 0x02a6df, 0x02a700, 0x02b738, 0x02b740, 0x02b81d, 0x02b820, 0x02cea1, 0x02ceb0, 0x02ebe0, 0x02f800, 0x02fa1d, 0x030000, 0x03134a)); } @@ -2168,7 +2214,7 @@ private static void populateLOWER() { 0x001f30, 0x001f37, 0x001f40, 0x001f45, 0x001f50, 0x001f57, 0x001f60, 0x001f67, 0x001f70, 0x001f7d, 0x001f80, 0x001f87, 0x001f90, 0x001f97, 0x001fa0, 0x001fa7, 0x001fb0, 0x001fb4, 0x001fb6, 0x001fb7, 0x001fbe, 0x001fbe, 0x001fc2, 0x001fc4, 0x001fc6, 0x001fc7, 0x001fd0, 0x001fd3, 0x001fd6, 0x001fd7, 0x001fe0, 0x001fe7, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ff7, 0x002071, 0x002071, 0x00207f, 0x00207f, 0x002090, 0x00209c, 0x00210a, 0x00210a, 0x00210e, 0x00210f, 0x002113, 0x002113, 0x00212f, 0x00212f, 0x002134, - 0x002134, 0x002139, 0x002139, 0x00213c, 0x00213d, 0x002146, 0x002149, 0x00214e, 0x00214e, 0x002170, 0x00217f, 0x002184, 0x002184, 0x0024d0, 0x0024e9, 0x002c30, 0x002c5e, + 0x002134, 0x002139, 0x002139, 0x00213c, 0x00213d, 0x002146, 0x002149, 0x00214e, 0x00214e, 0x002170, 0x00217f, 0x002184, 0x002184, 0x0024d0, 0x0024e9, 0x002c30, 0x002c5f, 0x002c61, 0x002c61, 0x002c65, 0x002c66, 0x002c68, 0x002c68, 0x002c6a, 0x002c6a, 0x002c6c, 0x002c6c, 0x002c71, 0x002c71, 0x002c73, 0x002c74, 0x002c76, 0x002c7d, 0x002c81, 0x002c81, 0x002c83, 0x002c83, 0x002c85, 0x002c85, 0x002c87, 0x002c87, 0x002c89, 0x002c89, 0x002c8b, 0x002c8b, 0x002c8d, 0x002c8d, 0x002c8f, 0x002c8f, 0x002c91, 0x002c91, 0x002c93, 0x002c93, 0x002c95, 0x002c95, 0x002c97, 0x002c97, 0x002c99, 0x002c99, 0x002c9b, 0x002c9b, 0x002c9d, 0x002c9d, 0x002c9f, 0x002c9f, 0x002ca1, 0x002ca1, 0x002ca3, @@ -2188,12 +2234,14 @@ private static void populateLOWER() { 0x00a76b, 0x00a76b, 0x00a76d, 0x00a76d, 0x00a76f, 0x00a778, 0x00a77a, 0x00a77a, 0x00a77c, 0x00a77c, 0x00a77f, 0x00a77f, 0x00a781, 0x00a781, 0x00a783, 0x00a783, 0x00a785, 0x00a785, 0x00a787, 0x00a787, 0x00a78c, 0x00a78c, 0x00a78e, 0x00a78e, 0x00a791, 0x00a791, 0x00a793, 0x00a795, 0x00a797, 0x00a797, 0x00a799, 0x00a799, 0x00a79b, 0x00a79b, 0x00a79d, 0x00a79d, 0x00a79f, 0x00a79f, 0x00a7a1, 0x00a7a1, 0x00a7a3, 0x00a7a3, 0x00a7a5, 0x00a7a5, 0x00a7a7, 0x00a7a7, 0x00a7a9, 0x00a7a9, 0x00a7af, 0x00a7af, 0x00a7b5, - 0x00a7b5, 0x00a7b7, 0x00a7b7, 0x00a7b9, 0x00a7b9, 0x00a7bb, 0x00a7bb, 0x00a7bd, 0x00a7bd, 0x00a7bf, 0x00a7bf, 0x00a7c3, 0x00a7c3, 0x00a7c8, 0x00a7c8, 0x00a7ca, 0x00a7ca, - 0x00a7f6, 0x00a7f6, 0x00a7f8, 0x00a7fa, 0x00ab30, 0x00ab5a, 0x00ab5c, 0x00ab68, 0x00ab70, 0x00abbf, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, 0x00ff41, 0x00ff5a, 0x010428, - 0x01044f, 0x0104d8, 0x0104fb, 0x010cc0, 0x010cf2, 0x0118c0, 0x0118df, 0x016e60, 0x016e7f, 0x01d41a, 0x01d433, 0x01d44e, 0x01d454, 0x01d456, 0x01d467, 0x01d482, 0x01d49b, - 0x01d4b6, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d4cf, 0x01d4ea, 0x01d503, 0x01d51e, 0x01d537, 0x01d552, 0x01d56b, 0x01d586, 0x01d59f, 0x01d5ba, - 0x01d5d3, 0x01d5ee, 0x01d607, 0x01d622, 0x01d63b, 0x01d656, 0x01d66f, 0x01d68a, 0x01d6a5, 0x01d6c2, 0x01d6da, 0x01d6dc, 0x01d6e1, 0x01d6fc, 0x01d714, 0x01d716, 0x01d71b, - 0x01d736, 0x01d74e, 0x01d750, 0x01d755, 0x01d770, 0x01d788, 0x01d78a, 0x01d78f, 0x01d7aa, 0x01d7c2, 0x01d7c4, 0x01d7c9, 0x01d7cb, 0x01d7cb, 0x01e922, 0x01e943)); + 0x00a7b5, 0x00a7b7, 0x00a7b7, 0x00a7b9, 0x00a7b9, 0x00a7bb, 0x00a7bb, 0x00a7bd, 0x00a7bd, 0x00a7bf, 0x00a7bf, 0x00a7c1, 0x00a7c1, 0x00a7c3, 0x00a7c3, 0x00a7c8, 0x00a7c8, + 0x00a7ca, 0x00a7ca, 0x00a7d1, 0x00a7d1, 0x00a7d3, 0x00a7d3, 0x00a7d5, 0x00a7d5, 0x00a7d7, 0x00a7d7, 0x00a7d9, 0x00a7d9, 0x00a7f6, 0x00a7f6, 0x00a7f8, 0x00a7fa, 0x00ab30, + 0x00ab5a, 0x00ab5c, 0x00ab68, 0x00ab70, 0x00abbf, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, 0x00ff41, 0x00ff5a, 0x010428, 0x01044f, 0x0104d8, 0x0104fb, 0x010597, 0x0105a1, + 0x0105a3, 0x0105b1, 0x0105b3, 0x0105b9, 0x0105bb, 0x0105bc, 0x010780, 0x010780, 0x010783, 0x010785, 0x010787, 0x0107b0, 0x0107b2, 0x0107ba, 0x010cc0, 0x010cf2, 0x0118c0, + 0x0118df, 0x016e60, 0x016e7f, 0x01d41a, 0x01d433, 0x01d44e, 0x01d454, 0x01d456, 0x01d467, 0x01d482, 0x01d49b, 0x01d4b6, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, + 0x01d4c5, 0x01d4cf, 0x01d4ea, 0x01d503, 0x01d51e, 0x01d537, 0x01d552, 0x01d56b, 0x01d586, 0x01d59f, 0x01d5ba, 0x01d5d3, 0x01d5ee, 0x01d607, 0x01d622, 0x01d63b, 0x01d656, + 0x01d66f, 0x01d68a, 0x01d6a5, 0x01d6c2, 0x01d6da, 0x01d6dc, 0x01d6e1, 0x01d6fc, 0x01d714, 0x01d716, 0x01d71b, 0x01d736, 0x01d74e, 0x01d750, 0x01d755, 0x01d770, 0x01d788, + 0x01d78a, 0x01d78f, 0x01d7aa, 0x01d7c2, 0x01d7c4, 0x01d7c9, 0x01d7cb, 0x01d7cb, 0x01df00, 0x01df09, 0x01df0b, 0x01df1e, 0x01e922, 0x01e943)); } private static void populateMATH() { @@ -2249,46 +2297,45 @@ private static void populateRADICAL() { } private static void populateSD() { - SET_ENCODINGS.put("SD", - CodePointSet.createNoDedup(0x000069, 0x00006a, 0x00012f, 0x00012f, 0x000249, 0x000249, 0x000268, 0x000268, 0x00029d, 0x00029d, 0x0002b2, 0x0002b2, 0x0003f3, 0x0003f3, 0x000456, - 0x000456, 0x000458, 0x000458, 0x001d62, 0x001d62, 0x001d96, 0x001d96, 0x001da4, 0x001da4, 0x001da8, 0x001da8, 0x001e2d, 0x001e2d, 0x001ecb, 0x001ecb, 0x002071, - 0x002071, 0x002148, 0x002149, 0x002c7c, 0x002c7c, 0x01d422, 0x01d423, 0x01d456, 0x01d457, 0x01d48a, 0x01d48b, 0x01d4be, 0x01d4bf, 0x01d4f2, 0x01d4f3, 0x01d526, - 0x01d527, 0x01d55a, 0x01d55b, 0x01d58e, 0x01d58f, 0x01d5c2, 0x01d5c3, 0x01d5f6, 0x01d5f7, 0x01d62a, 0x01d62b, 0x01d65e, 0x01d65f, 0x01d692, 0x01d693)); + SET_ENCODINGS.put("SD", CodePointSet.createNoDedup(0x000069, 0x00006a, 0x00012f, 0x00012f, 0x000249, 0x000249, 0x000268, 0x000268, 0x00029d, 0x00029d, 0x0002b2, 0x0002b2, 0x0003f3, 0x0003f3, + 0x000456, 0x000456, 0x000458, 0x000458, 0x001d62, 0x001d62, 0x001d96, 0x001d96, 0x001da4, 0x001da4, 0x001da8, 0x001da8, 0x001e2d, 0x001e2d, 0x001ecb, 0x001ecb, 0x002071, + 0x002071, 0x002148, 0x002149, 0x002c7c, 0x002c7c, 0x01d422, 0x01d423, 0x01d456, 0x01d457, 0x01d48a, 0x01d48b, 0x01d4be, 0x01d4bf, 0x01d4f2, 0x01d4f3, 0x01d526, 0x01d527, + 0x01d55a, 0x01d55b, 0x01d58e, 0x01d58f, 0x01d5c2, 0x01d5c3, 0x01d5f6, 0x01d5f7, 0x01d62a, 0x01d62b, 0x01d65e, 0x01d65f, 0x01d692, 0x01d693, 0x01df1a, 0x01df1a)); } private static void populateSTERM() { SET_ENCODINGS.put("STerm", - CodePointSet.createNoDedup(0x000021, 0x000021, 0x00002e, 0x00002e, 0x00003f, 0x00003f, 0x000589, 0x000589, 0x00061e, 0x00061f, 0x0006d4, 0x0006d4, 0x000700, 0x000702, 0x0007f9, + CodePointSet.createNoDedup(0x000021, 0x000021, 0x00002e, 0x00002e, 0x00003f, 0x00003f, 0x000589, 0x000589, 0x00061d, 0x00061f, 0x0006d4, 0x0006d4, 0x000700, 0x000702, 0x0007f9, 0x0007f9, 0x000837, 0x000837, 0x000839, 0x000839, 0x00083d, 0x00083e, 0x000964, 0x000965, 0x00104a, 0x00104b, 0x001362, 0x001362, 0x001367, 0x001368, 0x00166e, - 0x00166e, 0x001735, 0x001736, 0x001803, 0x001803, 0x001809, 0x001809, 0x001944, 0x001945, 0x001aa8, 0x001aab, 0x001b5a, 0x001b5b, 0x001b5e, 0x001b5f, 0x001c3b, - 0x001c3c, 0x001c7e, 0x001c7f, 0x00203c, 0x00203d, 0x002047, 0x002049, 0x002e2e, 0x002e2e, 0x002e3c, 0x002e3c, 0x003002, 0x003002, 0x00a4ff, 0x00a4ff, 0x00a60e, - 0x00a60f, 0x00a6f3, 0x00a6f3, 0x00a6f7, 0x00a6f7, 0x00a876, 0x00a877, 0x00a8ce, 0x00a8cf, 0x00a92f, 0x00a92f, 0x00a9c8, 0x00a9c9, 0x00aa5d, 0x00aa5f, 0x00aaf0, - 0x00aaf1, 0x00abeb, 0x00abeb, 0x00fe52, 0x00fe52, 0x00fe56, 0x00fe57, 0x00ff01, 0x00ff01, 0x00ff0e, 0x00ff0e, 0x00ff1f, 0x00ff1f, 0x00ff61, 0x00ff61, 0x010a56, - 0x010a57, 0x010f55, 0x010f59, 0x011047, 0x011048, 0x0110be, 0x0110c1, 0x011141, 0x011143, 0x0111c5, 0x0111c6, 0x0111cd, 0x0111cd, 0x0111de, 0x0111df, 0x011238, - 0x011239, 0x01123b, 0x01123c, 0x0112a9, 0x0112a9, 0x01144b, 0x01144c, 0x0115c2, 0x0115c3, 0x0115c9, 0x0115d7, 0x011641, 0x011642, 0x01173c, 0x01173e, 0x011944, - 0x011944, 0x011946, 0x011946, 0x011a42, 0x011a43, 0x011a9b, 0x011a9c, 0x011c41, 0x011c42, 0x011ef7, 0x011ef8, 0x016a6e, 0x016a6f, 0x016af5, 0x016af5, 0x016b37, - 0x016b38, 0x016b44, 0x016b44, 0x016e98, 0x016e98, 0x01bc9f, 0x01bc9f, 0x01da88, 0x01da88)); + 0x00166e, 0x001735, 0x001736, 0x001803, 0x001803, 0x001809, 0x001809, 0x001944, 0x001945, 0x001aa8, 0x001aab, 0x001b5a, 0x001b5b, 0x001b5e, 0x001b5f, 0x001b7d, + 0x001b7e, 0x001c3b, 0x001c3c, 0x001c7e, 0x001c7f, 0x00203c, 0x00203d, 0x002047, 0x002049, 0x002e2e, 0x002e2e, 0x002e3c, 0x002e3c, 0x002e53, 0x002e54, 0x003002, + 0x003002, 0x00a4ff, 0x00a4ff, 0x00a60e, 0x00a60f, 0x00a6f3, 0x00a6f3, 0x00a6f7, 0x00a6f7, 0x00a876, 0x00a877, 0x00a8ce, 0x00a8cf, 0x00a92f, 0x00a92f, 0x00a9c8, + 0x00a9c9, 0x00aa5d, 0x00aa5f, 0x00aaf0, 0x00aaf1, 0x00abeb, 0x00abeb, 0x00fe52, 0x00fe52, 0x00fe56, 0x00fe57, 0x00ff01, 0x00ff01, 0x00ff0e, 0x00ff0e, 0x00ff1f, + 0x00ff1f, 0x00ff61, 0x00ff61, 0x010a56, 0x010a57, 0x010f55, 0x010f59, 0x010f86, 0x010f89, 0x011047, 0x011048, 0x0110be, 0x0110c1, 0x011141, 0x011143, 0x0111c5, + 0x0111c6, 0x0111cd, 0x0111cd, 0x0111de, 0x0111df, 0x011238, 0x011239, 0x01123b, 0x01123c, 0x0112a9, 0x0112a9, 0x01144b, 0x01144c, 0x0115c2, 0x0115c3, 0x0115c9, + 0x0115d7, 0x011641, 0x011642, 0x01173c, 0x01173e, 0x011944, 0x011944, 0x011946, 0x011946, 0x011a42, 0x011a43, 0x011a9b, 0x011a9c, 0x011c41, 0x011c42, 0x011ef7, + 0x011ef8, 0x016a6e, 0x016a6f, 0x016af5, 0x016af5, 0x016b37, 0x016b38, 0x016b44, 0x016b44, 0x016e98, 0x016e98, 0x01bc9f, 0x01bc9f, 0x01da88, 0x01da88)); } private static void populateTERM() { SET_ENCODINGS.put("Term", CodePointSet.createNoDedup(0x000021, 0x000021, 0x00002c, 0x00002c, 0x00002e, 0x00002e, 0x00003a, 0x00003b, 0x00003f, 0x00003f, 0x00037e, 0x00037e, 0x000387, 0x000387, - 0x000589, 0x000589, 0x0005c3, 0x0005c3, 0x00060c, 0x00060c, 0x00061b, 0x00061b, 0x00061e, 0x00061f, 0x0006d4, 0x0006d4, 0x000700, 0x00070a, 0x00070c, 0x00070c, 0x0007f8, + 0x000589, 0x000589, 0x0005c3, 0x0005c3, 0x00060c, 0x00060c, 0x00061b, 0x00061b, 0x00061d, 0x00061f, 0x0006d4, 0x0006d4, 0x000700, 0x00070a, 0x00070c, 0x00070c, 0x0007f8, 0x0007f9, 0x000830, 0x00083e, 0x00085e, 0x00085e, 0x000964, 0x000965, 0x000e5a, 0x000e5b, 0x000f08, 0x000f08, 0x000f0d, 0x000f12, 0x00104a, 0x00104b, 0x001361, 0x001368, 0x00166e, 0x00166e, 0x0016eb, 0x0016ed, 0x001735, 0x001736, 0x0017d4, 0x0017d6, 0x0017da, 0x0017da, 0x001802, 0x001805, 0x001808, 0x001809, 0x001944, 0x001945, 0x001aa8, - 0x001aab, 0x001b5a, 0x001b5b, 0x001b5d, 0x001b5f, 0x001c3b, 0x001c3f, 0x001c7e, 0x001c7f, 0x00203c, 0x00203d, 0x002047, 0x002049, 0x002e2e, 0x002e2e, 0x002e3c, 0x002e3c, - 0x002e41, 0x002e41, 0x002e4c, 0x002e4c, 0x002e4e, 0x002e4f, 0x003001, 0x003002, 0x00a4fe, 0x00a4ff, 0x00a60d, 0x00a60f, 0x00a6f3, 0x00a6f7, 0x00a876, 0x00a877, 0x00a8ce, - 0x00a8cf, 0x00a92f, 0x00a92f, 0x00a9c7, 0x00a9c9, 0x00aa5d, 0x00aa5f, 0x00aadf, 0x00aadf, 0x00aaf0, 0x00aaf1, 0x00abeb, 0x00abeb, 0x00fe50, 0x00fe52, 0x00fe54, 0x00fe57, - 0x00ff01, 0x00ff01, 0x00ff0c, 0x00ff0c, 0x00ff0e, 0x00ff0e, 0x00ff1a, 0x00ff1b, 0x00ff1f, 0x00ff1f, 0x00ff61, 0x00ff61, 0x00ff64, 0x00ff64, 0x01039f, 0x01039f, 0x0103d0, - 0x0103d0, 0x010857, 0x010857, 0x01091f, 0x01091f, 0x010a56, 0x010a57, 0x010af0, 0x010af5, 0x010b3a, 0x010b3f, 0x010b99, 0x010b9c, 0x010f55, 0x010f59, 0x011047, 0x01104d, - 0x0110be, 0x0110c1, 0x011141, 0x011143, 0x0111c5, 0x0111c6, 0x0111cd, 0x0111cd, 0x0111de, 0x0111df, 0x011238, 0x01123c, 0x0112a9, 0x0112a9, 0x01144b, 0x01144d, 0x01145a, - 0x01145b, 0x0115c2, 0x0115c5, 0x0115c9, 0x0115d7, 0x011641, 0x011642, 0x01173c, 0x01173e, 0x011944, 0x011944, 0x011946, 0x011946, 0x011a42, 0x011a43, 0x011a9b, 0x011a9c, - 0x011aa1, 0x011aa2, 0x011c41, 0x011c43, 0x011c71, 0x011c71, 0x011ef7, 0x011ef8, 0x012470, 0x012474, 0x016a6e, 0x016a6f, 0x016af5, 0x016af5, 0x016b37, 0x016b39, 0x016b44, - 0x016b44, 0x016e97, 0x016e98, 0x01bc9f, 0x01bc9f, 0x01da87, 0x01da8a)); + 0x001aab, 0x001b5a, 0x001b5b, 0x001b5d, 0x001b5f, 0x001b7d, 0x001b7e, 0x001c3b, 0x001c3f, 0x001c7e, 0x001c7f, 0x00203c, 0x00203d, 0x002047, 0x002049, 0x002e2e, 0x002e2e, + 0x002e3c, 0x002e3c, 0x002e41, 0x002e41, 0x002e4c, 0x002e4c, 0x002e4e, 0x002e4f, 0x002e53, 0x002e54, 0x003001, 0x003002, 0x00a4fe, 0x00a4ff, 0x00a60d, 0x00a60f, 0x00a6f3, + 0x00a6f7, 0x00a876, 0x00a877, 0x00a8ce, 0x00a8cf, 0x00a92f, 0x00a92f, 0x00a9c7, 0x00a9c9, 0x00aa5d, 0x00aa5f, 0x00aadf, 0x00aadf, 0x00aaf0, 0x00aaf1, 0x00abeb, 0x00abeb, + 0x00fe50, 0x00fe52, 0x00fe54, 0x00fe57, 0x00ff01, 0x00ff01, 0x00ff0c, 0x00ff0c, 0x00ff0e, 0x00ff0e, 0x00ff1a, 0x00ff1b, 0x00ff1f, 0x00ff1f, 0x00ff61, 0x00ff61, 0x00ff64, + 0x00ff64, 0x01039f, 0x01039f, 0x0103d0, 0x0103d0, 0x010857, 0x010857, 0x01091f, 0x01091f, 0x010a56, 0x010a57, 0x010af0, 0x010af5, 0x010b3a, 0x010b3f, 0x010b99, 0x010b9c, + 0x010f55, 0x010f59, 0x010f86, 0x010f89, 0x011047, 0x01104d, 0x0110be, 0x0110c1, 0x011141, 0x011143, 0x0111c5, 0x0111c6, 0x0111cd, 0x0111cd, 0x0111de, 0x0111df, 0x011238, + 0x01123c, 0x0112a9, 0x0112a9, 0x01144b, 0x01144d, 0x01145a, 0x01145b, 0x0115c2, 0x0115c5, 0x0115c9, 0x0115d7, 0x011641, 0x011642, 0x01173c, 0x01173e, 0x011944, 0x011944, + 0x011946, 0x011946, 0x011a42, 0x011a43, 0x011a9b, 0x011a9c, 0x011aa1, 0x011aa2, 0x011c41, 0x011c43, 0x011c71, 0x011c71, 0x011ef7, 0x011ef8, 0x012470, 0x012474, 0x016a6e, + 0x016a6f, 0x016af5, 0x016af5, 0x016b37, 0x016b39, 0x016b44, 0x016b44, 0x016e97, 0x016e98, 0x01bc9f, 0x01bc9f, 0x01da87, 0x01da8a)); } private static void populateUIDEO() { - SET_ENCODINGS.put("UIdeo", CodePointSet.createNoDedup(0x003400, 0x004dbf, 0x004e00, 0x009ffc, 0x00fa0e, 0x00fa0f, 0x00fa11, 0x00fa11, 0x00fa13, 0x00fa14, 0x00fa1f, 0x00fa1f, 0x00fa21, - 0x00fa21, 0x00fa23, 0x00fa24, 0x00fa27, 0x00fa29, 0x020000, 0x02a6dd, 0x02a700, 0x02b734, 0x02b740, 0x02b81d, 0x02b820, 0x02cea1, 0x02ceb0, 0x02ebe0, 0x030000, 0x03134a)); + SET_ENCODINGS.put("UIdeo", CodePointSet.createNoDedup(0x003400, 0x004dbf, 0x004e00, 0x009fff, 0x00fa0e, 0x00fa0f, 0x00fa11, 0x00fa11, 0x00fa13, 0x00fa14, 0x00fa1f, 0x00fa1f, 0x00fa21, + 0x00fa21, 0x00fa23, 0x00fa24, 0x00fa27, 0x00fa29, 0x020000, 0x02a6df, 0x02a700, 0x02b738, 0x02b740, 0x02b81d, 0x02b820, 0x02cea1, 0x02ceb0, 0x02ebe0, 0x030000, 0x03134a)); } private static void populateUPPER() { @@ -2343,7 +2390,7 @@ private static void populateUPPER() { 0x001f48, 0x001f4d, 0x001f59, 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f5f, 0x001f68, 0x001f6f, 0x001fb8, 0x001fbb, 0x001fc8, 0x001fcb, 0x001fd8, 0x001fdb, 0x001fe8, 0x001fec, 0x001ff8, 0x001ffb, 0x002102, 0x002102, 0x002107, 0x002107, 0x00210b, 0x00210d, 0x002110, 0x002112, 0x002115, 0x002115, 0x002119, 0x00211d, 0x002124, 0x002124, 0x002126, 0x002126, 0x002128, 0x002128, 0x00212a, 0x00212d, 0x002130, 0x002133, 0x00213e, 0x00213f, 0x002145, 0x002145, 0x002160, 0x00216f, 0x002183, - 0x002183, 0x0024b6, 0x0024cf, 0x002c00, 0x002c2e, 0x002c60, 0x002c60, 0x002c62, 0x002c64, 0x002c67, 0x002c67, 0x002c69, 0x002c69, 0x002c6b, 0x002c6b, 0x002c6d, 0x002c70, + 0x002183, 0x0024b6, 0x0024cf, 0x002c00, 0x002c2f, 0x002c60, 0x002c60, 0x002c62, 0x002c64, 0x002c67, 0x002c67, 0x002c69, 0x002c69, 0x002c6b, 0x002c6b, 0x002c6d, 0x002c70, 0x002c72, 0x002c72, 0x002c75, 0x002c75, 0x002c7e, 0x002c80, 0x002c82, 0x002c82, 0x002c84, 0x002c84, 0x002c86, 0x002c86, 0x002c88, 0x002c88, 0x002c8a, 0x002c8a, 0x002c8c, 0x002c8c, 0x002c8e, 0x002c8e, 0x002c90, 0x002c90, 0x002c92, 0x002c92, 0x002c94, 0x002c94, 0x002c96, 0x002c96, 0x002c98, 0x002c98, 0x002c9a, 0x002c9a, 0x002c9c, 0x002c9c, 0x002c9e, 0x002c9e, 0x002ca0, 0x002ca0, 0x002ca2, 0x002ca2, 0x002ca4, 0x002ca4, 0x002ca6, 0x002ca6, 0x002ca8, 0x002ca8, 0x002caa, 0x002caa, 0x002cac, 0x002cac, 0x002cae, @@ -2362,16 +2409,17 @@ private static void populateUPPER() { 0x00a76a, 0x00a76c, 0x00a76c, 0x00a76e, 0x00a76e, 0x00a779, 0x00a779, 0x00a77b, 0x00a77b, 0x00a77d, 0x00a77e, 0x00a780, 0x00a780, 0x00a782, 0x00a782, 0x00a784, 0x00a784, 0x00a786, 0x00a786, 0x00a78b, 0x00a78b, 0x00a78d, 0x00a78d, 0x00a790, 0x00a790, 0x00a792, 0x00a792, 0x00a796, 0x00a796, 0x00a798, 0x00a798, 0x00a79a, 0x00a79a, 0x00a79c, 0x00a79c, 0x00a79e, 0x00a79e, 0x00a7a0, 0x00a7a0, 0x00a7a2, 0x00a7a2, 0x00a7a4, 0x00a7a4, 0x00a7a6, 0x00a7a6, 0x00a7a8, 0x00a7a8, 0x00a7aa, 0x00a7ae, 0x00a7b0, 0x00a7b4, - 0x00a7b6, 0x00a7b6, 0x00a7b8, 0x00a7b8, 0x00a7ba, 0x00a7ba, 0x00a7bc, 0x00a7bc, 0x00a7be, 0x00a7be, 0x00a7c2, 0x00a7c2, 0x00a7c4, 0x00a7c7, 0x00a7c9, 0x00a7c9, 0x00a7f5, - 0x00a7f5, 0x00ff21, 0x00ff3a, 0x010400, 0x010427, 0x0104b0, 0x0104d3, 0x010c80, 0x010cb2, 0x0118a0, 0x0118bf, 0x016e40, 0x016e5f, 0x01d400, 0x01d419, 0x01d434, 0x01d44d, - 0x01d468, 0x01d481, 0x01d49c, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b5, 0x01d4d0, 0x01d4e9, 0x01d504, - 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d538, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, - 0x01d56c, 0x01d585, 0x01d5a0, 0x01d5b9, 0x01d5d4, 0x01d5ed, 0x01d608, 0x01d621, 0x01d63c, 0x01d655, 0x01d670, 0x01d689, 0x01d6a8, 0x01d6c0, 0x01d6e2, 0x01d6fa, 0x01d71c, - 0x01d734, 0x01d756, 0x01d76e, 0x01d790, 0x01d7a8, 0x01d7ca, 0x01d7ca, 0x01e900, 0x01e921, 0x01f130, 0x01f149, 0x01f150, 0x01f169, 0x01f170, 0x01f189)); + 0x00a7b6, 0x00a7b6, 0x00a7b8, 0x00a7b8, 0x00a7ba, 0x00a7ba, 0x00a7bc, 0x00a7bc, 0x00a7be, 0x00a7be, 0x00a7c0, 0x00a7c0, 0x00a7c2, 0x00a7c2, 0x00a7c4, 0x00a7c7, 0x00a7c9, + 0x00a7c9, 0x00a7d0, 0x00a7d0, 0x00a7d6, 0x00a7d6, 0x00a7d8, 0x00a7d8, 0x00a7f5, 0x00a7f5, 0x00ff21, 0x00ff3a, 0x010400, 0x010427, 0x0104b0, 0x0104d3, 0x010570, 0x01057a, + 0x01057c, 0x01058a, 0x01058c, 0x010592, 0x010594, 0x010595, 0x010c80, 0x010cb2, 0x0118a0, 0x0118bf, 0x016e40, 0x016e5f, 0x01d400, 0x01d419, 0x01d434, 0x01d44d, 0x01d468, + 0x01d481, 0x01d49c, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b5, 0x01d4d0, 0x01d4e9, 0x01d504, 0x01d505, + 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d538, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d56c, + 0x01d585, 0x01d5a0, 0x01d5b9, 0x01d5d4, 0x01d5ed, 0x01d608, 0x01d621, 0x01d63c, 0x01d655, 0x01d670, 0x01d689, 0x01d6a8, 0x01d6c0, 0x01d6e2, 0x01d6fa, 0x01d71c, 0x01d734, + 0x01d756, 0x01d76e, 0x01d790, 0x01d7a8, 0x01d7ca, 0x01d7ca, 0x01e900, 0x01e921, 0x01f130, 0x01f149, 0x01f150, 0x01f169, 0x01f170, 0x01f189)); } private static void populateVS() { - SET_ENCODINGS.put("VS", CodePointSet.createNoDedup(0x00180b, 0x00180d, 0x00fe00, 0x00fe0f, 0x0e0100, 0x0e01ef)); + SET_ENCODINGS.put("VS", CodePointSet.createNoDedup(0x00180b, 0x00180d, 0x00180f, 0x00180f, 0x00fe00, 0x00fe0f, 0x0e0100, 0x0e01ef)); } private static void populateWSPACE() { @@ -2386,7 +2434,7 @@ private static void populateXIDC() { 0x000483, 0x000487, 0x00048a, 0x00052f, 0x000531, 0x000556, 0x000559, 0x000559, 0x000560, 0x000588, 0x000591, 0x0005bd, 0x0005bf, 0x0005bf, 0x0005c1, 0x0005c2, 0x0005c4, 0x0005c5, 0x0005c7, 0x0005c7, 0x0005d0, 0x0005ea, 0x0005ef, 0x0005f2, 0x000610, 0x00061a, 0x000620, 0x000669, 0x00066e, 0x0006d3, 0x0006d5, 0x0006dc, 0x0006df, 0x0006e8, 0x0006ea, 0x0006fc, 0x0006ff, 0x0006ff, 0x000710, 0x00074a, 0x00074d, 0x0007b1, 0x0007c0, 0x0007f5, 0x0007fa, 0x0007fa, 0x0007fd, 0x0007fd, 0x000800, 0x00082d, 0x000840, - 0x00085b, 0x000860, 0x00086a, 0x0008a0, 0x0008b4, 0x0008b6, 0x0008c7, 0x0008d3, 0x0008e1, 0x0008e3, 0x000963, 0x000966, 0x00096f, 0x000971, 0x000983, 0x000985, 0x00098c, + 0x00085b, 0x000860, 0x00086a, 0x000870, 0x000887, 0x000889, 0x00088e, 0x000898, 0x0008e1, 0x0008e3, 0x000963, 0x000966, 0x00096f, 0x000971, 0x000983, 0x000985, 0x00098c, 0x00098f, 0x000990, 0x000993, 0x0009a8, 0x0009aa, 0x0009b0, 0x0009b2, 0x0009b2, 0x0009b6, 0x0009b9, 0x0009bc, 0x0009c4, 0x0009c7, 0x0009c8, 0x0009cb, 0x0009ce, 0x0009d7, 0x0009d7, 0x0009dc, 0x0009dd, 0x0009df, 0x0009e3, 0x0009e6, 0x0009f1, 0x0009fc, 0x0009fc, 0x0009fe, 0x0009fe, 0x000a01, 0x000a03, 0x000a05, 0x000a0a, 0x000a0f, 0x000a10, 0x000a13, 0x000a28, 0x000a2a, 0x000a30, 0x000a32, 0x000a33, 0x000a35, 0x000a36, 0x000a38, 0x000a39, 0x000a3c, 0x000a3c, 0x000a3e, 0x000a42, 0x000a47, 0x000a48, 0x000a4b, @@ -2396,77 +2444,80 @@ private static void populateXIDC() { 0x000b3c, 0x000b44, 0x000b47, 0x000b48, 0x000b4b, 0x000b4d, 0x000b55, 0x000b57, 0x000b5c, 0x000b5d, 0x000b5f, 0x000b63, 0x000b66, 0x000b6f, 0x000b71, 0x000b71, 0x000b82, 0x000b83, 0x000b85, 0x000b8a, 0x000b8e, 0x000b90, 0x000b92, 0x000b95, 0x000b99, 0x000b9a, 0x000b9c, 0x000b9c, 0x000b9e, 0x000b9f, 0x000ba3, 0x000ba4, 0x000ba8, 0x000baa, 0x000bae, 0x000bb9, 0x000bbe, 0x000bc2, 0x000bc6, 0x000bc8, 0x000bca, 0x000bcd, 0x000bd0, 0x000bd0, 0x000bd7, 0x000bd7, 0x000be6, 0x000bef, 0x000c00, 0x000c0c, 0x000c0e, - 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3d, 0x000c44, 0x000c46, 0x000c48, 0x000c4a, 0x000c4d, 0x000c55, 0x000c56, 0x000c58, 0x000c5a, 0x000c60, 0x000c63, - 0x000c66, 0x000c6f, 0x000c80, 0x000c83, 0x000c85, 0x000c8c, 0x000c8e, 0x000c90, 0x000c92, 0x000ca8, 0x000caa, 0x000cb3, 0x000cb5, 0x000cb9, 0x000cbc, 0x000cc4, 0x000cc6, - 0x000cc8, 0x000cca, 0x000ccd, 0x000cd5, 0x000cd6, 0x000cde, 0x000cde, 0x000ce0, 0x000ce3, 0x000ce6, 0x000cef, 0x000cf1, 0x000cf2, 0x000d00, 0x000d0c, 0x000d0e, 0x000d10, - 0x000d12, 0x000d44, 0x000d46, 0x000d48, 0x000d4a, 0x000d4e, 0x000d54, 0x000d57, 0x000d5f, 0x000d63, 0x000d66, 0x000d6f, 0x000d7a, 0x000d7f, 0x000d81, 0x000d83, 0x000d85, - 0x000d96, 0x000d9a, 0x000db1, 0x000db3, 0x000dbb, 0x000dbd, 0x000dbd, 0x000dc0, 0x000dc6, 0x000dca, 0x000dca, 0x000dcf, 0x000dd4, 0x000dd6, 0x000dd6, 0x000dd8, 0x000ddf, - 0x000de6, 0x000def, 0x000df2, 0x000df3, 0x000e01, 0x000e3a, 0x000e40, 0x000e4e, 0x000e50, 0x000e59, 0x000e81, 0x000e82, 0x000e84, 0x000e84, 0x000e86, 0x000e8a, 0x000e8c, - 0x000ea3, 0x000ea5, 0x000ea5, 0x000ea7, 0x000ebd, 0x000ec0, 0x000ec4, 0x000ec6, 0x000ec6, 0x000ec8, 0x000ecd, 0x000ed0, 0x000ed9, 0x000edc, 0x000edf, 0x000f00, 0x000f00, - 0x000f18, 0x000f19, 0x000f20, 0x000f29, 0x000f35, 0x000f35, 0x000f37, 0x000f37, 0x000f39, 0x000f39, 0x000f3e, 0x000f47, 0x000f49, 0x000f6c, 0x000f71, 0x000f84, 0x000f86, - 0x000f97, 0x000f99, 0x000fbc, 0x000fc6, 0x000fc6, 0x001000, 0x001049, 0x001050, 0x00109d, 0x0010a0, 0x0010c5, 0x0010c7, 0x0010c7, 0x0010cd, 0x0010cd, 0x0010d0, 0x0010fa, - 0x0010fc, 0x001248, 0x00124a, 0x00124d, 0x001250, 0x001256, 0x001258, 0x001258, 0x00125a, 0x00125d, 0x001260, 0x001288, 0x00128a, 0x00128d, 0x001290, 0x0012b0, 0x0012b2, - 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, 0x0012d8, 0x001310, 0x001312, 0x001315, 0x001318, 0x00135a, 0x00135d, 0x00135f, - 0x001369, 0x001371, 0x001380, 0x00138f, 0x0013a0, 0x0013f5, 0x0013f8, 0x0013fd, 0x001401, 0x00166c, 0x00166f, 0x00167f, 0x001681, 0x00169a, 0x0016a0, 0x0016ea, 0x0016ee, - 0x0016f8, 0x001700, 0x00170c, 0x00170e, 0x001714, 0x001720, 0x001734, 0x001740, 0x001753, 0x001760, 0x00176c, 0x00176e, 0x001770, 0x001772, 0x001773, 0x001780, 0x0017d3, - 0x0017d7, 0x0017d7, 0x0017dc, 0x0017dd, 0x0017e0, 0x0017e9, 0x00180b, 0x00180d, 0x001810, 0x001819, 0x001820, 0x001878, 0x001880, 0x0018aa, 0x0018b0, 0x0018f5, 0x001900, + 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3c, 0x000c44, 0x000c46, 0x000c48, 0x000c4a, 0x000c4d, 0x000c55, 0x000c56, 0x000c58, 0x000c5a, 0x000c5d, 0x000c5d, + 0x000c60, 0x000c63, 0x000c66, 0x000c6f, 0x000c80, 0x000c83, 0x000c85, 0x000c8c, 0x000c8e, 0x000c90, 0x000c92, 0x000ca8, 0x000caa, 0x000cb3, 0x000cb5, 0x000cb9, 0x000cbc, + 0x000cc4, 0x000cc6, 0x000cc8, 0x000cca, 0x000ccd, 0x000cd5, 0x000cd6, 0x000cdd, 0x000cde, 0x000ce0, 0x000ce3, 0x000ce6, 0x000cef, 0x000cf1, 0x000cf2, 0x000d00, 0x000d0c, + 0x000d0e, 0x000d10, 0x000d12, 0x000d44, 0x000d46, 0x000d48, 0x000d4a, 0x000d4e, 0x000d54, 0x000d57, 0x000d5f, 0x000d63, 0x000d66, 0x000d6f, 0x000d7a, 0x000d7f, 0x000d81, + 0x000d83, 0x000d85, 0x000d96, 0x000d9a, 0x000db1, 0x000db3, 0x000dbb, 0x000dbd, 0x000dbd, 0x000dc0, 0x000dc6, 0x000dca, 0x000dca, 0x000dcf, 0x000dd4, 0x000dd6, 0x000dd6, + 0x000dd8, 0x000ddf, 0x000de6, 0x000def, 0x000df2, 0x000df3, 0x000e01, 0x000e3a, 0x000e40, 0x000e4e, 0x000e50, 0x000e59, 0x000e81, 0x000e82, 0x000e84, 0x000e84, 0x000e86, + 0x000e8a, 0x000e8c, 0x000ea3, 0x000ea5, 0x000ea5, 0x000ea7, 0x000ebd, 0x000ec0, 0x000ec4, 0x000ec6, 0x000ec6, 0x000ec8, 0x000ecd, 0x000ed0, 0x000ed9, 0x000edc, 0x000edf, + 0x000f00, 0x000f00, 0x000f18, 0x000f19, 0x000f20, 0x000f29, 0x000f35, 0x000f35, 0x000f37, 0x000f37, 0x000f39, 0x000f39, 0x000f3e, 0x000f47, 0x000f49, 0x000f6c, 0x000f71, + 0x000f84, 0x000f86, 0x000f97, 0x000f99, 0x000fbc, 0x000fc6, 0x000fc6, 0x001000, 0x001049, 0x001050, 0x00109d, 0x0010a0, 0x0010c5, 0x0010c7, 0x0010c7, 0x0010cd, 0x0010cd, + 0x0010d0, 0x0010fa, 0x0010fc, 0x001248, 0x00124a, 0x00124d, 0x001250, 0x001256, 0x001258, 0x001258, 0x00125a, 0x00125d, 0x001260, 0x001288, 0x00128a, 0x00128d, 0x001290, + 0x0012b0, 0x0012b2, 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, 0x0012d8, 0x001310, 0x001312, 0x001315, 0x001318, 0x00135a, + 0x00135d, 0x00135f, 0x001369, 0x001371, 0x001380, 0x00138f, 0x0013a0, 0x0013f5, 0x0013f8, 0x0013fd, 0x001401, 0x00166c, 0x00166f, 0x00167f, 0x001681, 0x00169a, 0x0016a0, + 0x0016ea, 0x0016ee, 0x0016f8, 0x001700, 0x001715, 0x00171f, 0x001734, 0x001740, 0x001753, 0x001760, 0x00176c, 0x00176e, 0x001770, 0x001772, 0x001773, 0x001780, 0x0017d3, + 0x0017d7, 0x0017d7, 0x0017dc, 0x0017dd, 0x0017e0, 0x0017e9, 0x00180b, 0x00180d, 0x00180f, 0x001819, 0x001820, 0x001878, 0x001880, 0x0018aa, 0x0018b0, 0x0018f5, 0x001900, 0x00191e, 0x001920, 0x00192b, 0x001930, 0x00193b, 0x001946, 0x00196d, 0x001970, 0x001974, 0x001980, 0x0019ab, 0x0019b0, 0x0019c9, 0x0019d0, 0x0019da, 0x001a00, 0x001a1b, - 0x001a20, 0x001a5e, 0x001a60, 0x001a7c, 0x001a7f, 0x001a89, 0x001a90, 0x001a99, 0x001aa7, 0x001aa7, 0x001ab0, 0x001abd, 0x001abf, 0x001ac0, 0x001b00, 0x001b4b, 0x001b50, + 0x001a20, 0x001a5e, 0x001a60, 0x001a7c, 0x001a7f, 0x001a89, 0x001a90, 0x001a99, 0x001aa7, 0x001aa7, 0x001ab0, 0x001abd, 0x001abf, 0x001ace, 0x001b00, 0x001b4c, 0x001b50, 0x001b59, 0x001b6b, 0x001b73, 0x001b80, 0x001bf3, 0x001c00, 0x001c37, 0x001c40, 0x001c49, 0x001c4d, 0x001c7d, 0x001c80, 0x001c88, 0x001c90, 0x001cba, 0x001cbd, 0x001cbf, - 0x001cd0, 0x001cd2, 0x001cd4, 0x001cfa, 0x001d00, 0x001df9, 0x001dfb, 0x001f15, 0x001f18, 0x001f1d, 0x001f20, 0x001f45, 0x001f48, 0x001f4d, 0x001f50, 0x001f57, 0x001f59, - 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f7d, 0x001f80, 0x001fb4, 0x001fb6, 0x001fbc, 0x001fbe, 0x001fbe, 0x001fc2, 0x001fc4, 0x001fc6, 0x001fcc, - 0x001fd0, 0x001fd3, 0x001fd6, 0x001fdb, 0x001fe0, 0x001fec, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ffc, 0x00203f, 0x002040, 0x002054, 0x002054, 0x002071, 0x002071, 0x00207f, - 0x00207f, 0x002090, 0x00209c, 0x0020d0, 0x0020dc, 0x0020e1, 0x0020e1, 0x0020e5, 0x0020f0, 0x002102, 0x002102, 0x002107, 0x002107, 0x00210a, 0x002113, 0x002115, 0x002115, - 0x002118, 0x00211d, 0x002124, 0x002124, 0x002126, 0x002126, 0x002128, 0x002128, 0x00212a, 0x002139, 0x00213c, 0x00213f, 0x002145, 0x002149, 0x00214e, 0x00214e, 0x002160, - 0x002188, 0x002c00, 0x002c2e, 0x002c30, 0x002c5e, 0x002c60, 0x002ce4, 0x002ceb, 0x002cf3, 0x002d00, 0x002d25, 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, 0x002d30, 0x002d67, - 0x002d6f, 0x002d6f, 0x002d7f, 0x002d96, 0x002da0, 0x002da6, 0x002da8, 0x002dae, 0x002db0, 0x002db6, 0x002db8, 0x002dbe, 0x002dc0, 0x002dc6, 0x002dc8, 0x002dce, 0x002dd0, - 0x002dd6, 0x002dd8, 0x002dde, 0x002de0, 0x002dff, 0x003005, 0x003007, 0x003021, 0x00302f, 0x003031, 0x003035, 0x003038, 0x00303c, 0x003041, 0x003096, 0x003099, 0x00309a, - 0x00309d, 0x00309f, 0x0030a1, 0x0030fa, 0x0030fc, 0x0030ff, 0x003105, 0x00312f, 0x003131, 0x00318e, 0x0031a0, 0x0031bf, 0x0031f0, 0x0031ff, 0x003400, 0x004dbf, 0x004e00, - 0x009ffc, 0x00a000, 0x00a48c, 0x00a4d0, 0x00a4fd, 0x00a500, 0x00a60c, 0x00a610, 0x00a62b, 0x00a640, 0x00a66f, 0x00a674, 0x00a67d, 0x00a67f, 0x00a6f1, 0x00a717, 0x00a71f, - 0x00a722, 0x00a788, 0x00a78b, 0x00a7bf, 0x00a7c2, 0x00a7ca, 0x00a7f5, 0x00a827, 0x00a82c, 0x00a82c, 0x00a840, 0x00a873, 0x00a880, 0x00a8c5, 0x00a8d0, 0x00a8d9, 0x00a8e0, - 0x00a8f7, 0x00a8fb, 0x00a8fb, 0x00a8fd, 0x00a92d, 0x00a930, 0x00a953, 0x00a960, 0x00a97c, 0x00a980, 0x00a9c0, 0x00a9cf, 0x00a9d9, 0x00a9e0, 0x00a9fe, 0x00aa00, 0x00aa36, - 0x00aa40, 0x00aa4d, 0x00aa50, 0x00aa59, 0x00aa60, 0x00aa76, 0x00aa7a, 0x00aac2, 0x00aadb, 0x00aadd, 0x00aae0, 0x00aaef, 0x00aaf2, 0x00aaf6, 0x00ab01, 0x00ab06, 0x00ab09, - 0x00ab0e, 0x00ab11, 0x00ab16, 0x00ab20, 0x00ab26, 0x00ab28, 0x00ab2e, 0x00ab30, 0x00ab5a, 0x00ab5c, 0x00ab69, 0x00ab70, 0x00abea, 0x00abec, 0x00abed, 0x00abf0, 0x00abf9, - 0x00ac00, 0x00d7a3, 0x00d7b0, 0x00d7c6, 0x00d7cb, 0x00d7fb, 0x00f900, 0x00fa6d, 0x00fa70, 0x00fad9, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, 0x00fb1d, 0x00fb28, 0x00fb2a, - 0x00fb36, 0x00fb38, 0x00fb3c, 0x00fb3e, 0x00fb3e, 0x00fb40, 0x00fb41, 0x00fb43, 0x00fb44, 0x00fb46, 0x00fbb1, 0x00fbd3, 0x00fc5d, 0x00fc64, 0x00fd3d, 0x00fd50, 0x00fd8f, - 0x00fd92, 0x00fdc7, 0x00fdf0, 0x00fdf9, 0x00fe00, 0x00fe0f, 0x00fe20, 0x00fe2f, 0x00fe33, 0x00fe34, 0x00fe4d, 0x00fe4f, 0x00fe71, 0x00fe71, 0x00fe73, 0x00fe73, 0x00fe77, - 0x00fe77, 0x00fe79, 0x00fe79, 0x00fe7b, 0x00fe7b, 0x00fe7d, 0x00fe7d, 0x00fe7f, 0x00fefc, 0x00ff10, 0x00ff19, 0x00ff21, 0x00ff3a, 0x00ff3f, 0x00ff3f, 0x00ff41, 0x00ff5a, - 0x00ff66, 0x00ffbe, 0x00ffc2, 0x00ffc7, 0x00ffca, 0x00ffcf, 0x00ffd2, 0x00ffd7, 0x00ffda, 0x00ffdc, 0x010000, 0x01000b, 0x01000d, 0x010026, 0x010028, 0x01003a, 0x01003c, - 0x01003d, 0x01003f, 0x01004d, 0x010050, 0x01005d, 0x010080, 0x0100fa, 0x010140, 0x010174, 0x0101fd, 0x0101fd, 0x010280, 0x01029c, 0x0102a0, 0x0102d0, 0x0102e0, 0x0102e0, - 0x010300, 0x01031f, 0x01032d, 0x01034a, 0x010350, 0x01037a, 0x010380, 0x01039d, 0x0103a0, 0x0103c3, 0x0103c8, 0x0103cf, 0x0103d1, 0x0103d5, 0x010400, 0x01049d, 0x0104a0, - 0x0104a9, 0x0104b0, 0x0104d3, 0x0104d8, 0x0104fb, 0x010500, 0x010527, 0x010530, 0x010563, 0x010600, 0x010736, 0x010740, 0x010755, 0x010760, 0x010767, 0x010800, 0x010805, - 0x010808, 0x010808, 0x01080a, 0x010835, 0x010837, 0x010838, 0x01083c, 0x01083c, 0x01083f, 0x010855, 0x010860, 0x010876, 0x010880, 0x01089e, 0x0108e0, 0x0108f2, 0x0108f4, - 0x0108f5, 0x010900, 0x010915, 0x010920, 0x010939, 0x010980, 0x0109b7, 0x0109be, 0x0109bf, 0x010a00, 0x010a03, 0x010a05, 0x010a06, 0x010a0c, 0x010a13, 0x010a15, 0x010a17, - 0x010a19, 0x010a35, 0x010a38, 0x010a3a, 0x010a3f, 0x010a3f, 0x010a60, 0x010a7c, 0x010a80, 0x010a9c, 0x010ac0, 0x010ac7, 0x010ac9, 0x010ae6, 0x010b00, 0x010b35, 0x010b40, - 0x010b55, 0x010b60, 0x010b72, 0x010b80, 0x010b91, 0x010c00, 0x010c48, 0x010c80, 0x010cb2, 0x010cc0, 0x010cf2, 0x010d00, 0x010d27, 0x010d30, 0x010d39, 0x010e80, 0x010ea9, - 0x010eab, 0x010eac, 0x010eb0, 0x010eb1, 0x010f00, 0x010f1c, 0x010f27, 0x010f27, 0x010f30, 0x010f50, 0x010fb0, 0x010fc4, 0x010fe0, 0x010ff6, 0x011000, 0x011046, 0x011066, - 0x01106f, 0x01107f, 0x0110ba, 0x0110d0, 0x0110e8, 0x0110f0, 0x0110f9, 0x011100, 0x011134, 0x011136, 0x01113f, 0x011144, 0x011147, 0x011150, 0x011173, 0x011176, 0x011176, - 0x011180, 0x0111c4, 0x0111c9, 0x0111cc, 0x0111ce, 0x0111da, 0x0111dc, 0x0111dc, 0x011200, 0x011211, 0x011213, 0x011237, 0x01123e, 0x01123e, 0x011280, 0x011286, 0x011288, - 0x011288, 0x01128a, 0x01128d, 0x01128f, 0x01129d, 0x01129f, 0x0112a8, 0x0112b0, 0x0112ea, 0x0112f0, 0x0112f9, 0x011300, 0x011303, 0x011305, 0x01130c, 0x01130f, 0x011310, - 0x011313, 0x011328, 0x01132a, 0x011330, 0x011332, 0x011333, 0x011335, 0x011339, 0x01133b, 0x011344, 0x011347, 0x011348, 0x01134b, 0x01134d, 0x011350, 0x011350, 0x011357, - 0x011357, 0x01135d, 0x011363, 0x011366, 0x01136c, 0x011370, 0x011374, 0x011400, 0x01144a, 0x011450, 0x011459, 0x01145e, 0x011461, 0x011480, 0x0114c5, 0x0114c7, 0x0114c7, - 0x0114d0, 0x0114d9, 0x011580, 0x0115b5, 0x0115b8, 0x0115c0, 0x0115d8, 0x0115dd, 0x011600, 0x011640, 0x011644, 0x011644, 0x011650, 0x011659, 0x011680, 0x0116b8, 0x0116c0, - 0x0116c9, 0x011700, 0x01171a, 0x01171d, 0x01172b, 0x011730, 0x011739, 0x011800, 0x01183a, 0x0118a0, 0x0118e9, 0x0118ff, 0x011906, 0x011909, 0x011909, 0x01190c, 0x011913, - 0x011915, 0x011916, 0x011918, 0x011935, 0x011937, 0x011938, 0x01193b, 0x011943, 0x011950, 0x011959, 0x0119a0, 0x0119a7, 0x0119aa, 0x0119d7, 0x0119da, 0x0119e1, 0x0119e3, - 0x0119e4, 0x011a00, 0x011a3e, 0x011a47, 0x011a47, 0x011a50, 0x011a99, 0x011a9d, 0x011a9d, 0x011ac0, 0x011af8, 0x011c00, 0x011c08, 0x011c0a, 0x011c36, 0x011c38, 0x011c40, - 0x011c50, 0x011c59, 0x011c72, 0x011c8f, 0x011c92, 0x011ca7, 0x011ca9, 0x011cb6, 0x011d00, 0x011d06, 0x011d08, 0x011d09, 0x011d0b, 0x011d36, 0x011d3a, 0x011d3a, 0x011d3c, - 0x011d3d, 0x011d3f, 0x011d47, 0x011d50, 0x011d59, 0x011d60, 0x011d65, 0x011d67, 0x011d68, 0x011d6a, 0x011d8e, 0x011d90, 0x011d91, 0x011d93, 0x011d98, 0x011da0, 0x011da9, - 0x011ee0, 0x011ef6, 0x011fb0, 0x011fb0, 0x012000, 0x012399, 0x012400, 0x01246e, 0x012480, 0x012543, 0x013000, 0x01342e, 0x014400, 0x014646, 0x016800, 0x016a38, 0x016a40, - 0x016a5e, 0x016a60, 0x016a69, 0x016ad0, 0x016aed, 0x016af0, 0x016af4, 0x016b00, 0x016b36, 0x016b40, 0x016b43, 0x016b50, 0x016b59, 0x016b63, 0x016b77, 0x016b7d, 0x016b8f, - 0x016e40, 0x016e7f, 0x016f00, 0x016f4a, 0x016f4f, 0x016f87, 0x016f8f, 0x016f9f, 0x016fe0, 0x016fe1, 0x016fe3, 0x016fe4, 0x016ff0, 0x016ff1, 0x017000, 0x0187f7, 0x018800, - 0x018cd5, 0x018d00, 0x018d08, 0x01b000, 0x01b11e, 0x01b150, 0x01b152, 0x01b164, 0x01b167, 0x01b170, 0x01b2fb, 0x01bc00, 0x01bc6a, 0x01bc70, 0x01bc7c, 0x01bc80, 0x01bc88, - 0x01bc90, 0x01bc99, 0x01bc9d, 0x01bc9e, 0x01d165, 0x01d169, 0x01d16d, 0x01d172, 0x01d17b, 0x01d182, 0x01d185, 0x01d18b, 0x01d1aa, 0x01d1ad, 0x01d242, 0x01d244, 0x01d400, - 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, - 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, - 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d6c0, 0x01d6c2, 0x01d6da, 0x01d6dc, 0x01d6fa, 0x01d6fc, 0x01d714, 0x01d716, 0x01d734, 0x01d736, 0x01d74e, 0x01d750, 0x01d76e, - 0x01d770, 0x01d788, 0x01d78a, 0x01d7a8, 0x01d7aa, 0x01d7c2, 0x01d7c4, 0x01d7cb, 0x01d7ce, 0x01d7ff, 0x01da00, 0x01da36, 0x01da3b, 0x01da6c, 0x01da75, 0x01da75, 0x01da84, - 0x01da84, 0x01da9b, 0x01da9f, 0x01daa1, 0x01daaf, 0x01e000, 0x01e006, 0x01e008, 0x01e018, 0x01e01b, 0x01e021, 0x01e023, 0x01e024, 0x01e026, 0x01e02a, 0x01e100, 0x01e12c, - 0x01e130, 0x01e13d, 0x01e140, 0x01e149, 0x01e14e, 0x01e14e, 0x01e2c0, 0x01e2f9, 0x01e800, 0x01e8c4, 0x01e8d0, 0x01e8d6, 0x01e900, 0x01e94b, 0x01e950, 0x01e959, 0x01ee00, - 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, 0x01ee39, 0x01ee3b, 0x01ee3b, - 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, 0x01ee57, 0x01ee57, 0x01ee59, - 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, 0x01ee72, 0x01ee74, 0x01ee77, - 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, 0x01ee80, 0x01ee89, 0x01ee8b, 0x01ee9b, 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, 0x01fbf0, 0x01fbf9, 0x020000, - 0x02a6dd, 0x02a700, 0x02b734, 0x02b740, 0x02b81d, 0x02b820, 0x02cea1, 0x02ceb0, 0x02ebe0, 0x02f800, 0x02fa1d, 0x030000, 0x03134a, 0x0e0100, 0x0e01ef)); + 0x001cd0, 0x001cd2, 0x001cd4, 0x001cfa, 0x001d00, 0x001f15, 0x001f18, 0x001f1d, 0x001f20, 0x001f45, 0x001f48, 0x001f4d, 0x001f50, 0x001f57, 0x001f59, 0x001f59, 0x001f5b, + 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f7d, 0x001f80, 0x001fb4, 0x001fb6, 0x001fbc, 0x001fbe, 0x001fbe, 0x001fc2, 0x001fc4, 0x001fc6, 0x001fcc, 0x001fd0, 0x001fd3, + 0x001fd6, 0x001fdb, 0x001fe0, 0x001fec, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ffc, 0x00203f, 0x002040, 0x002054, 0x002054, 0x002071, 0x002071, 0x00207f, 0x00207f, 0x002090, + 0x00209c, 0x0020d0, 0x0020dc, 0x0020e1, 0x0020e1, 0x0020e5, 0x0020f0, 0x002102, 0x002102, 0x002107, 0x002107, 0x00210a, 0x002113, 0x002115, 0x002115, 0x002118, 0x00211d, + 0x002124, 0x002124, 0x002126, 0x002126, 0x002128, 0x002128, 0x00212a, 0x002139, 0x00213c, 0x00213f, 0x002145, 0x002149, 0x00214e, 0x00214e, 0x002160, 0x002188, 0x002c00, + 0x002ce4, 0x002ceb, 0x002cf3, 0x002d00, 0x002d25, 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, 0x002d30, 0x002d67, 0x002d6f, 0x002d6f, 0x002d7f, 0x002d96, 0x002da0, 0x002da6, + 0x002da8, 0x002dae, 0x002db0, 0x002db6, 0x002db8, 0x002dbe, 0x002dc0, 0x002dc6, 0x002dc8, 0x002dce, 0x002dd0, 0x002dd6, 0x002dd8, 0x002dde, 0x002de0, 0x002dff, 0x003005, + 0x003007, 0x003021, 0x00302f, 0x003031, 0x003035, 0x003038, 0x00303c, 0x003041, 0x003096, 0x003099, 0x00309a, 0x00309d, 0x00309f, 0x0030a1, 0x0030fa, 0x0030fc, 0x0030ff, + 0x003105, 0x00312f, 0x003131, 0x00318e, 0x0031a0, 0x0031bf, 0x0031f0, 0x0031ff, 0x003400, 0x004dbf, 0x004e00, 0x00a48c, 0x00a4d0, 0x00a4fd, 0x00a500, 0x00a60c, 0x00a610, + 0x00a62b, 0x00a640, 0x00a66f, 0x00a674, 0x00a67d, 0x00a67f, 0x00a6f1, 0x00a717, 0x00a71f, 0x00a722, 0x00a788, 0x00a78b, 0x00a7ca, 0x00a7d0, 0x00a7d1, 0x00a7d3, 0x00a7d3, + 0x00a7d5, 0x00a7d9, 0x00a7f2, 0x00a827, 0x00a82c, 0x00a82c, 0x00a840, 0x00a873, 0x00a880, 0x00a8c5, 0x00a8d0, 0x00a8d9, 0x00a8e0, 0x00a8f7, 0x00a8fb, 0x00a8fb, 0x00a8fd, + 0x00a92d, 0x00a930, 0x00a953, 0x00a960, 0x00a97c, 0x00a980, 0x00a9c0, 0x00a9cf, 0x00a9d9, 0x00a9e0, 0x00a9fe, 0x00aa00, 0x00aa36, 0x00aa40, 0x00aa4d, 0x00aa50, 0x00aa59, + 0x00aa60, 0x00aa76, 0x00aa7a, 0x00aac2, 0x00aadb, 0x00aadd, 0x00aae0, 0x00aaef, 0x00aaf2, 0x00aaf6, 0x00ab01, 0x00ab06, 0x00ab09, 0x00ab0e, 0x00ab11, 0x00ab16, 0x00ab20, + 0x00ab26, 0x00ab28, 0x00ab2e, 0x00ab30, 0x00ab5a, 0x00ab5c, 0x00ab69, 0x00ab70, 0x00abea, 0x00abec, 0x00abed, 0x00abf0, 0x00abf9, 0x00ac00, 0x00d7a3, 0x00d7b0, 0x00d7c6, + 0x00d7cb, 0x00d7fb, 0x00f900, 0x00fa6d, 0x00fa70, 0x00fad9, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, 0x00fb1d, 0x00fb28, 0x00fb2a, 0x00fb36, 0x00fb38, 0x00fb3c, 0x00fb3e, + 0x00fb3e, 0x00fb40, 0x00fb41, 0x00fb43, 0x00fb44, 0x00fb46, 0x00fbb1, 0x00fbd3, 0x00fc5d, 0x00fc64, 0x00fd3d, 0x00fd50, 0x00fd8f, 0x00fd92, 0x00fdc7, 0x00fdf0, 0x00fdf9, + 0x00fe00, 0x00fe0f, 0x00fe20, 0x00fe2f, 0x00fe33, 0x00fe34, 0x00fe4d, 0x00fe4f, 0x00fe71, 0x00fe71, 0x00fe73, 0x00fe73, 0x00fe77, 0x00fe77, 0x00fe79, 0x00fe79, 0x00fe7b, + 0x00fe7b, 0x00fe7d, 0x00fe7d, 0x00fe7f, 0x00fefc, 0x00ff10, 0x00ff19, 0x00ff21, 0x00ff3a, 0x00ff3f, 0x00ff3f, 0x00ff41, 0x00ff5a, 0x00ff66, 0x00ffbe, 0x00ffc2, 0x00ffc7, + 0x00ffca, 0x00ffcf, 0x00ffd2, 0x00ffd7, 0x00ffda, 0x00ffdc, 0x010000, 0x01000b, 0x01000d, 0x010026, 0x010028, 0x01003a, 0x01003c, 0x01003d, 0x01003f, 0x01004d, 0x010050, + 0x01005d, 0x010080, 0x0100fa, 0x010140, 0x010174, 0x0101fd, 0x0101fd, 0x010280, 0x01029c, 0x0102a0, 0x0102d0, 0x0102e0, 0x0102e0, 0x010300, 0x01031f, 0x01032d, 0x01034a, + 0x010350, 0x01037a, 0x010380, 0x01039d, 0x0103a0, 0x0103c3, 0x0103c8, 0x0103cf, 0x0103d1, 0x0103d5, 0x010400, 0x01049d, 0x0104a0, 0x0104a9, 0x0104b0, 0x0104d3, 0x0104d8, + 0x0104fb, 0x010500, 0x010527, 0x010530, 0x010563, 0x010570, 0x01057a, 0x01057c, 0x01058a, 0x01058c, 0x010592, 0x010594, 0x010595, 0x010597, 0x0105a1, 0x0105a3, 0x0105b1, + 0x0105b3, 0x0105b9, 0x0105bb, 0x0105bc, 0x010600, 0x010736, 0x010740, 0x010755, 0x010760, 0x010767, 0x010780, 0x010785, 0x010787, 0x0107b0, 0x0107b2, 0x0107ba, 0x010800, + 0x010805, 0x010808, 0x010808, 0x01080a, 0x010835, 0x010837, 0x010838, 0x01083c, 0x01083c, 0x01083f, 0x010855, 0x010860, 0x010876, 0x010880, 0x01089e, 0x0108e0, 0x0108f2, + 0x0108f4, 0x0108f5, 0x010900, 0x010915, 0x010920, 0x010939, 0x010980, 0x0109b7, 0x0109be, 0x0109bf, 0x010a00, 0x010a03, 0x010a05, 0x010a06, 0x010a0c, 0x010a13, 0x010a15, + 0x010a17, 0x010a19, 0x010a35, 0x010a38, 0x010a3a, 0x010a3f, 0x010a3f, 0x010a60, 0x010a7c, 0x010a80, 0x010a9c, 0x010ac0, 0x010ac7, 0x010ac9, 0x010ae6, 0x010b00, 0x010b35, + 0x010b40, 0x010b55, 0x010b60, 0x010b72, 0x010b80, 0x010b91, 0x010c00, 0x010c48, 0x010c80, 0x010cb2, 0x010cc0, 0x010cf2, 0x010d00, 0x010d27, 0x010d30, 0x010d39, 0x010e80, + 0x010ea9, 0x010eab, 0x010eac, 0x010eb0, 0x010eb1, 0x010f00, 0x010f1c, 0x010f27, 0x010f27, 0x010f30, 0x010f50, 0x010f70, 0x010f85, 0x010fb0, 0x010fc4, 0x010fe0, 0x010ff6, + 0x011000, 0x011046, 0x011066, 0x011075, 0x01107f, 0x0110ba, 0x0110c2, 0x0110c2, 0x0110d0, 0x0110e8, 0x0110f0, 0x0110f9, 0x011100, 0x011134, 0x011136, 0x01113f, 0x011144, + 0x011147, 0x011150, 0x011173, 0x011176, 0x011176, 0x011180, 0x0111c4, 0x0111c9, 0x0111cc, 0x0111ce, 0x0111da, 0x0111dc, 0x0111dc, 0x011200, 0x011211, 0x011213, 0x011237, + 0x01123e, 0x01123e, 0x011280, 0x011286, 0x011288, 0x011288, 0x01128a, 0x01128d, 0x01128f, 0x01129d, 0x01129f, 0x0112a8, 0x0112b0, 0x0112ea, 0x0112f0, 0x0112f9, 0x011300, + 0x011303, 0x011305, 0x01130c, 0x01130f, 0x011310, 0x011313, 0x011328, 0x01132a, 0x011330, 0x011332, 0x011333, 0x011335, 0x011339, 0x01133b, 0x011344, 0x011347, 0x011348, + 0x01134b, 0x01134d, 0x011350, 0x011350, 0x011357, 0x011357, 0x01135d, 0x011363, 0x011366, 0x01136c, 0x011370, 0x011374, 0x011400, 0x01144a, 0x011450, 0x011459, 0x01145e, + 0x011461, 0x011480, 0x0114c5, 0x0114c7, 0x0114c7, 0x0114d0, 0x0114d9, 0x011580, 0x0115b5, 0x0115b8, 0x0115c0, 0x0115d8, 0x0115dd, 0x011600, 0x011640, 0x011644, 0x011644, + 0x011650, 0x011659, 0x011680, 0x0116b8, 0x0116c0, 0x0116c9, 0x011700, 0x01171a, 0x01171d, 0x01172b, 0x011730, 0x011739, 0x011740, 0x011746, 0x011800, 0x01183a, 0x0118a0, + 0x0118e9, 0x0118ff, 0x011906, 0x011909, 0x011909, 0x01190c, 0x011913, 0x011915, 0x011916, 0x011918, 0x011935, 0x011937, 0x011938, 0x01193b, 0x011943, 0x011950, 0x011959, + 0x0119a0, 0x0119a7, 0x0119aa, 0x0119d7, 0x0119da, 0x0119e1, 0x0119e3, 0x0119e4, 0x011a00, 0x011a3e, 0x011a47, 0x011a47, 0x011a50, 0x011a99, 0x011a9d, 0x011a9d, 0x011ab0, + 0x011af8, 0x011c00, 0x011c08, 0x011c0a, 0x011c36, 0x011c38, 0x011c40, 0x011c50, 0x011c59, 0x011c72, 0x011c8f, 0x011c92, 0x011ca7, 0x011ca9, 0x011cb6, 0x011d00, 0x011d06, + 0x011d08, 0x011d09, 0x011d0b, 0x011d36, 0x011d3a, 0x011d3a, 0x011d3c, 0x011d3d, 0x011d3f, 0x011d47, 0x011d50, 0x011d59, 0x011d60, 0x011d65, 0x011d67, 0x011d68, 0x011d6a, + 0x011d8e, 0x011d90, 0x011d91, 0x011d93, 0x011d98, 0x011da0, 0x011da9, 0x011ee0, 0x011ef6, 0x011fb0, 0x011fb0, 0x012000, 0x012399, 0x012400, 0x01246e, 0x012480, 0x012543, + 0x012f90, 0x012ff0, 0x013000, 0x01342e, 0x014400, 0x014646, 0x016800, 0x016a38, 0x016a40, 0x016a5e, 0x016a60, 0x016a69, 0x016a70, 0x016abe, 0x016ac0, 0x016ac9, 0x016ad0, + 0x016aed, 0x016af0, 0x016af4, 0x016b00, 0x016b36, 0x016b40, 0x016b43, 0x016b50, 0x016b59, 0x016b63, 0x016b77, 0x016b7d, 0x016b8f, 0x016e40, 0x016e7f, 0x016f00, 0x016f4a, + 0x016f4f, 0x016f87, 0x016f8f, 0x016f9f, 0x016fe0, 0x016fe1, 0x016fe3, 0x016fe4, 0x016ff0, 0x016ff1, 0x017000, 0x0187f7, 0x018800, 0x018cd5, 0x018d00, 0x018d08, 0x01aff0, + 0x01aff3, 0x01aff5, 0x01affb, 0x01affd, 0x01affe, 0x01b000, 0x01b122, 0x01b150, 0x01b152, 0x01b164, 0x01b167, 0x01b170, 0x01b2fb, 0x01bc00, 0x01bc6a, 0x01bc70, 0x01bc7c, + 0x01bc80, 0x01bc88, 0x01bc90, 0x01bc99, 0x01bc9d, 0x01bc9e, 0x01cf00, 0x01cf2d, 0x01cf30, 0x01cf46, 0x01d165, 0x01d169, 0x01d16d, 0x01d172, 0x01d17b, 0x01d182, 0x01d185, + 0x01d18b, 0x01d1aa, 0x01d1ad, 0x01d242, 0x01d244, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, + 0x01d4ae, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, + 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d6c0, 0x01d6c2, 0x01d6da, 0x01d6dc, 0x01d6fa, 0x01d6fc, 0x01d714, + 0x01d716, 0x01d734, 0x01d736, 0x01d74e, 0x01d750, 0x01d76e, 0x01d770, 0x01d788, 0x01d78a, 0x01d7a8, 0x01d7aa, 0x01d7c2, 0x01d7c4, 0x01d7cb, 0x01d7ce, 0x01d7ff, 0x01da00, + 0x01da36, 0x01da3b, 0x01da6c, 0x01da75, 0x01da75, 0x01da84, 0x01da84, 0x01da9b, 0x01da9f, 0x01daa1, 0x01daaf, 0x01df00, 0x01df1e, 0x01e000, 0x01e006, 0x01e008, 0x01e018, + 0x01e01b, 0x01e021, 0x01e023, 0x01e024, 0x01e026, 0x01e02a, 0x01e100, 0x01e12c, 0x01e130, 0x01e13d, 0x01e140, 0x01e149, 0x01e14e, 0x01e14e, 0x01e290, 0x01e2ae, 0x01e2c0, + 0x01e2f9, 0x01e7e0, 0x01e7e6, 0x01e7e8, 0x01e7eb, 0x01e7ed, 0x01e7ee, 0x01e7f0, 0x01e7fe, 0x01e800, 0x01e8c4, 0x01e8d0, 0x01e8d6, 0x01e900, 0x01e94b, 0x01e950, 0x01e959, + 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, 0x01ee39, 0x01ee3b, + 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, 0x01ee57, 0x01ee57, + 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, 0x01ee72, 0x01ee74, + 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, 0x01ee80, 0x01ee89, 0x01ee8b, 0x01ee9b, 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, 0x01fbf0, 0x01fbf9, + 0x020000, 0x02a6df, 0x02a700, 0x02b738, 0x02b740, 0x02b81d, 0x02b820, 0x02cea1, 0x02ceb0, 0x02ebe0, 0x02f800, 0x02fa1d, 0x030000, 0x03134a, 0x0e0100, 0x0e01ef)); } private static void populateXIDS() { @@ -2475,38 +2526,38 @@ private static void populateXIDS() { 0x00037f, 0x000386, 0x000386, 0x000388, 0x00038a, 0x00038c, 0x00038c, 0x00038e, 0x0003a1, 0x0003a3, 0x0003f5, 0x0003f7, 0x000481, 0x00048a, 0x00052f, 0x000531, 0x000556, 0x000559, 0x000559, 0x000560, 0x000588, 0x0005d0, 0x0005ea, 0x0005ef, 0x0005f2, 0x000620, 0x00064a, 0x00066e, 0x00066f, 0x000671, 0x0006d3, 0x0006d5, 0x0006d5, 0x0006e5, 0x0006e6, 0x0006ee, 0x0006ef, 0x0006fa, 0x0006fc, 0x0006ff, 0x0006ff, 0x000710, 0x000710, 0x000712, 0x00072f, 0x00074d, 0x0007a5, 0x0007b1, 0x0007b1, 0x0007ca, 0x0007ea, - 0x0007f4, 0x0007f5, 0x0007fa, 0x0007fa, 0x000800, 0x000815, 0x00081a, 0x00081a, 0x000824, 0x000824, 0x000828, 0x000828, 0x000840, 0x000858, 0x000860, 0x00086a, 0x0008a0, - 0x0008b4, 0x0008b6, 0x0008c7, 0x000904, 0x000939, 0x00093d, 0x00093d, 0x000950, 0x000950, 0x000958, 0x000961, 0x000971, 0x000980, 0x000985, 0x00098c, 0x00098f, 0x000990, - 0x000993, 0x0009a8, 0x0009aa, 0x0009b0, 0x0009b2, 0x0009b2, 0x0009b6, 0x0009b9, 0x0009bd, 0x0009bd, 0x0009ce, 0x0009ce, 0x0009dc, 0x0009dd, 0x0009df, 0x0009e1, 0x0009f0, - 0x0009f1, 0x0009fc, 0x0009fc, 0x000a05, 0x000a0a, 0x000a0f, 0x000a10, 0x000a13, 0x000a28, 0x000a2a, 0x000a30, 0x000a32, 0x000a33, 0x000a35, 0x000a36, 0x000a38, 0x000a39, - 0x000a59, 0x000a5c, 0x000a5e, 0x000a5e, 0x000a72, 0x000a74, 0x000a85, 0x000a8d, 0x000a8f, 0x000a91, 0x000a93, 0x000aa8, 0x000aaa, 0x000ab0, 0x000ab2, 0x000ab3, 0x000ab5, - 0x000ab9, 0x000abd, 0x000abd, 0x000ad0, 0x000ad0, 0x000ae0, 0x000ae1, 0x000af9, 0x000af9, 0x000b05, 0x000b0c, 0x000b0f, 0x000b10, 0x000b13, 0x000b28, 0x000b2a, 0x000b30, - 0x000b32, 0x000b33, 0x000b35, 0x000b39, 0x000b3d, 0x000b3d, 0x000b5c, 0x000b5d, 0x000b5f, 0x000b61, 0x000b71, 0x000b71, 0x000b83, 0x000b83, 0x000b85, 0x000b8a, 0x000b8e, - 0x000b90, 0x000b92, 0x000b95, 0x000b99, 0x000b9a, 0x000b9c, 0x000b9c, 0x000b9e, 0x000b9f, 0x000ba3, 0x000ba4, 0x000ba8, 0x000baa, 0x000bae, 0x000bb9, 0x000bd0, 0x000bd0, - 0x000c05, 0x000c0c, 0x000c0e, 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3d, 0x000c3d, 0x000c58, 0x000c5a, 0x000c60, 0x000c61, 0x000c80, 0x000c80, 0x000c85, - 0x000c8c, 0x000c8e, 0x000c90, 0x000c92, 0x000ca8, 0x000caa, 0x000cb3, 0x000cb5, 0x000cb9, 0x000cbd, 0x000cbd, 0x000cde, 0x000cde, 0x000ce0, 0x000ce1, 0x000cf1, 0x000cf2, - 0x000d04, 0x000d0c, 0x000d0e, 0x000d10, 0x000d12, 0x000d3a, 0x000d3d, 0x000d3d, 0x000d4e, 0x000d4e, 0x000d54, 0x000d56, 0x000d5f, 0x000d61, 0x000d7a, 0x000d7f, 0x000d85, - 0x000d96, 0x000d9a, 0x000db1, 0x000db3, 0x000dbb, 0x000dbd, 0x000dbd, 0x000dc0, 0x000dc6, 0x000e01, 0x000e30, 0x000e32, 0x000e32, 0x000e40, 0x000e46, 0x000e81, 0x000e82, - 0x000e84, 0x000e84, 0x000e86, 0x000e8a, 0x000e8c, 0x000ea3, 0x000ea5, 0x000ea5, 0x000ea7, 0x000eb0, 0x000eb2, 0x000eb2, 0x000ebd, 0x000ebd, 0x000ec0, 0x000ec4, 0x000ec6, - 0x000ec6, 0x000edc, 0x000edf, 0x000f00, 0x000f00, 0x000f40, 0x000f47, 0x000f49, 0x000f6c, 0x000f88, 0x000f8c, 0x001000, 0x00102a, 0x00103f, 0x00103f, 0x001050, 0x001055, - 0x00105a, 0x00105d, 0x001061, 0x001061, 0x001065, 0x001066, 0x00106e, 0x001070, 0x001075, 0x001081, 0x00108e, 0x00108e, 0x0010a0, 0x0010c5, 0x0010c7, 0x0010c7, 0x0010cd, - 0x0010cd, 0x0010d0, 0x0010fa, 0x0010fc, 0x001248, 0x00124a, 0x00124d, 0x001250, 0x001256, 0x001258, 0x001258, 0x00125a, 0x00125d, 0x001260, 0x001288, 0x00128a, 0x00128d, - 0x001290, 0x0012b0, 0x0012b2, 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, 0x0012d8, 0x001310, 0x001312, 0x001315, 0x001318, - 0x00135a, 0x001380, 0x00138f, 0x0013a0, 0x0013f5, 0x0013f8, 0x0013fd, 0x001401, 0x00166c, 0x00166f, 0x00167f, 0x001681, 0x00169a, 0x0016a0, 0x0016ea, 0x0016ee, 0x0016f8, - 0x001700, 0x00170c, 0x00170e, 0x001711, 0x001720, 0x001731, 0x001740, 0x001751, 0x001760, 0x00176c, 0x00176e, 0x001770, 0x001780, 0x0017b3, 0x0017d7, 0x0017d7, 0x0017dc, - 0x0017dc, 0x001820, 0x001878, 0x001880, 0x0018a8, 0x0018aa, 0x0018aa, 0x0018b0, 0x0018f5, 0x001900, 0x00191e, 0x001950, 0x00196d, 0x001970, 0x001974, 0x001980, 0x0019ab, - 0x0019b0, 0x0019c9, 0x001a00, 0x001a16, 0x001a20, 0x001a54, 0x001aa7, 0x001aa7, 0x001b05, 0x001b33, 0x001b45, 0x001b4b, 0x001b83, 0x001ba0, 0x001bae, 0x001baf, 0x001bba, - 0x001be5, 0x001c00, 0x001c23, 0x001c4d, 0x001c4f, 0x001c5a, 0x001c7d, 0x001c80, 0x001c88, 0x001c90, 0x001cba, 0x001cbd, 0x001cbf, 0x001ce9, 0x001cec, 0x001cee, 0x001cf3, - 0x001cf5, 0x001cf6, 0x001cfa, 0x001cfa, 0x001d00, 0x001dbf, 0x001e00, 0x001f15, 0x001f18, 0x001f1d, 0x001f20, 0x001f45, 0x001f48, 0x001f4d, 0x001f50, 0x001f57, 0x001f59, - 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f7d, 0x001f80, 0x001fb4, 0x001fb6, 0x001fbc, 0x001fbe, 0x001fbe, 0x001fc2, 0x001fc4, 0x001fc6, 0x001fcc, - 0x001fd0, 0x001fd3, 0x001fd6, 0x001fdb, 0x001fe0, 0x001fec, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ffc, 0x002071, 0x002071, 0x00207f, 0x00207f, 0x002090, 0x00209c, 0x002102, - 0x002102, 0x002107, 0x002107, 0x00210a, 0x002113, 0x002115, 0x002115, 0x002118, 0x00211d, 0x002124, 0x002124, 0x002126, 0x002126, 0x002128, 0x002128, 0x00212a, 0x002139, - 0x00213c, 0x00213f, 0x002145, 0x002149, 0x00214e, 0x00214e, 0x002160, 0x002188, 0x002c00, 0x002c2e, 0x002c30, 0x002c5e, 0x002c60, 0x002ce4, 0x002ceb, 0x002cee, 0x002cf2, - 0x002cf3, 0x002d00, 0x002d25, 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, 0x002d30, 0x002d67, 0x002d6f, 0x002d6f, 0x002d80, 0x002d96, 0x002da0, 0x002da6, 0x002da8, 0x002dae, - 0x002db0, 0x002db6, 0x002db8, 0x002dbe, 0x002dc0, 0x002dc6, 0x002dc8, 0x002dce, 0x002dd0, 0x002dd6, 0x002dd8, 0x002dde, 0x003005, 0x003007, 0x003021, 0x003029, 0x003031, - 0x003035, 0x003038, 0x00303c, 0x003041, 0x003096, 0x00309d, 0x00309f, 0x0030a1, 0x0030fa, 0x0030fc, 0x0030ff, 0x003105, 0x00312f, 0x003131, 0x00318e, 0x0031a0, 0x0031bf, - 0x0031f0, 0x0031ff, 0x003400, 0x004dbf, 0x004e00, 0x009ffc, 0x00a000, 0x00a48c, 0x00a4d0, 0x00a4fd, 0x00a500, 0x00a60c, 0x00a610, 0x00a61f, 0x00a62a, 0x00a62b, 0x00a640, - 0x00a66e, 0x00a67f, 0x00a69d, 0x00a6a0, 0x00a6ef, 0x00a717, 0x00a71f, 0x00a722, 0x00a788, 0x00a78b, 0x00a7bf, 0x00a7c2, 0x00a7ca, 0x00a7f5, 0x00a801, 0x00a803, 0x00a805, + 0x0007f4, 0x0007f5, 0x0007fa, 0x0007fa, 0x000800, 0x000815, 0x00081a, 0x00081a, 0x000824, 0x000824, 0x000828, 0x000828, 0x000840, 0x000858, 0x000860, 0x00086a, 0x000870, + 0x000887, 0x000889, 0x00088e, 0x0008a0, 0x0008c9, 0x000904, 0x000939, 0x00093d, 0x00093d, 0x000950, 0x000950, 0x000958, 0x000961, 0x000971, 0x000980, 0x000985, 0x00098c, + 0x00098f, 0x000990, 0x000993, 0x0009a8, 0x0009aa, 0x0009b0, 0x0009b2, 0x0009b2, 0x0009b6, 0x0009b9, 0x0009bd, 0x0009bd, 0x0009ce, 0x0009ce, 0x0009dc, 0x0009dd, 0x0009df, + 0x0009e1, 0x0009f0, 0x0009f1, 0x0009fc, 0x0009fc, 0x000a05, 0x000a0a, 0x000a0f, 0x000a10, 0x000a13, 0x000a28, 0x000a2a, 0x000a30, 0x000a32, 0x000a33, 0x000a35, 0x000a36, + 0x000a38, 0x000a39, 0x000a59, 0x000a5c, 0x000a5e, 0x000a5e, 0x000a72, 0x000a74, 0x000a85, 0x000a8d, 0x000a8f, 0x000a91, 0x000a93, 0x000aa8, 0x000aaa, 0x000ab0, 0x000ab2, + 0x000ab3, 0x000ab5, 0x000ab9, 0x000abd, 0x000abd, 0x000ad0, 0x000ad0, 0x000ae0, 0x000ae1, 0x000af9, 0x000af9, 0x000b05, 0x000b0c, 0x000b0f, 0x000b10, 0x000b13, 0x000b28, + 0x000b2a, 0x000b30, 0x000b32, 0x000b33, 0x000b35, 0x000b39, 0x000b3d, 0x000b3d, 0x000b5c, 0x000b5d, 0x000b5f, 0x000b61, 0x000b71, 0x000b71, 0x000b83, 0x000b83, 0x000b85, + 0x000b8a, 0x000b8e, 0x000b90, 0x000b92, 0x000b95, 0x000b99, 0x000b9a, 0x000b9c, 0x000b9c, 0x000b9e, 0x000b9f, 0x000ba3, 0x000ba4, 0x000ba8, 0x000baa, 0x000bae, 0x000bb9, + 0x000bd0, 0x000bd0, 0x000c05, 0x000c0c, 0x000c0e, 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3d, 0x000c3d, 0x000c58, 0x000c5a, 0x000c5d, 0x000c5d, 0x000c60, + 0x000c61, 0x000c80, 0x000c80, 0x000c85, 0x000c8c, 0x000c8e, 0x000c90, 0x000c92, 0x000ca8, 0x000caa, 0x000cb3, 0x000cb5, 0x000cb9, 0x000cbd, 0x000cbd, 0x000cdd, 0x000cde, + 0x000ce0, 0x000ce1, 0x000cf1, 0x000cf2, 0x000d04, 0x000d0c, 0x000d0e, 0x000d10, 0x000d12, 0x000d3a, 0x000d3d, 0x000d3d, 0x000d4e, 0x000d4e, 0x000d54, 0x000d56, 0x000d5f, + 0x000d61, 0x000d7a, 0x000d7f, 0x000d85, 0x000d96, 0x000d9a, 0x000db1, 0x000db3, 0x000dbb, 0x000dbd, 0x000dbd, 0x000dc0, 0x000dc6, 0x000e01, 0x000e30, 0x000e32, 0x000e32, + 0x000e40, 0x000e46, 0x000e81, 0x000e82, 0x000e84, 0x000e84, 0x000e86, 0x000e8a, 0x000e8c, 0x000ea3, 0x000ea5, 0x000ea5, 0x000ea7, 0x000eb0, 0x000eb2, 0x000eb2, 0x000ebd, + 0x000ebd, 0x000ec0, 0x000ec4, 0x000ec6, 0x000ec6, 0x000edc, 0x000edf, 0x000f00, 0x000f00, 0x000f40, 0x000f47, 0x000f49, 0x000f6c, 0x000f88, 0x000f8c, 0x001000, 0x00102a, + 0x00103f, 0x00103f, 0x001050, 0x001055, 0x00105a, 0x00105d, 0x001061, 0x001061, 0x001065, 0x001066, 0x00106e, 0x001070, 0x001075, 0x001081, 0x00108e, 0x00108e, 0x0010a0, + 0x0010c5, 0x0010c7, 0x0010c7, 0x0010cd, 0x0010cd, 0x0010d0, 0x0010fa, 0x0010fc, 0x001248, 0x00124a, 0x00124d, 0x001250, 0x001256, 0x001258, 0x001258, 0x00125a, 0x00125d, + 0x001260, 0x001288, 0x00128a, 0x00128d, 0x001290, 0x0012b0, 0x0012b2, 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, 0x0012d8, + 0x001310, 0x001312, 0x001315, 0x001318, 0x00135a, 0x001380, 0x00138f, 0x0013a0, 0x0013f5, 0x0013f8, 0x0013fd, 0x001401, 0x00166c, 0x00166f, 0x00167f, 0x001681, 0x00169a, + 0x0016a0, 0x0016ea, 0x0016ee, 0x0016f8, 0x001700, 0x001711, 0x00171f, 0x001731, 0x001740, 0x001751, 0x001760, 0x00176c, 0x00176e, 0x001770, 0x001780, 0x0017b3, 0x0017d7, + 0x0017d7, 0x0017dc, 0x0017dc, 0x001820, 0x001878, 0x001880, 0x0018a8, 0x0018aa, 0x0018aa, 0x0018b0, 0x0018f5, 0x001900, 0x00191e, 0x001950, 0x00196d, 0x001970, 0x001974, + 0x001980, 0x0019ab, 0x0019b0, 0x0019c9, 0x001a00, 0x001a16, 0x001a20, 0x001a54, 0x001aa7, 0x001aa7, 0x001b05, 0x001b33, 0x001b45, 0x001b4c, 0x001b83, 0x001ba0, 0x001bae, + 0x001baf, 0x001bba, 0x001be5, 0x001c00, 0x001c23, 0x001c4d, 0x001c4f, 0x001c5a, 0x001c7d, 0x001c80, 0x001c88, 0x001c90, 0x001cba, 0x001cbd, 0x001cbf, 0x001ce9, 0x001cec, + 0x001cee, 0x001cf3, 0x001cf5, 0x001cf6, 0x001cfa, 0x001cfa, 0x001d00, 0x001dbf, 0x001e00, 0x001f15, 0x001f18, 0x001f1d, 0x001f20, 0x001f45, 0x001f48, 0x001f4d, 0x001f50, + 0x001f57, 0x001f59, 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f7d, 0x001f80, 0x001fb4, 0x001fb6, 0x001fbc, 0x001fbe, 0x001fbe, 0x001fc2, 0x001fc4, + 0x001fc6, 0x001fcc, 0x001fd0, 0x001fd3, 0x001fd6, 0x001fdb, 0x001fe0, 0x001fec, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ffc, 0x002071, 0x002071, 0x00207f, 0x00207f, 0x002090, + 0x00209c, 0x002102, 0x002102, 0x002107, 0x002107, 0x00210a, 0x002113, 0x002115, 0x002115, 0x002118, 0x00211d, 0x002124, 0x002124, 0x002126, 0x002126, 0x002128, 0x002128, + 0x00212a, 0x002139, 0x00213c, 0x00213f, 0x002145, 0x002149, 0x00214e, 0x00214e, 0x002160, 0x002188, 0x002c00, 0x002ce4, 0x002ceb, 0x002cee, 0x002cf2, 0x002cf3, 0x002d00, + 0x002d25, 0x002d27, 0x002d27, 0x002d2d, 0x002d2d, 0x002d30, 0x002d67, 0x002d6f, 0x002d6f, 0x002d80, 0x002d96, 0x002da0, 0x002da6, 0x002da8, 0x002dae, 0x002db0, 0x002db6, + 0x002db8, 0x002dbe, 0x002dc0, 0x002dc6, 0x002dc8, 0x002dce, 0x002dd0, 0x002dd6, 0x002dd8, 0x002dde, 0x003005, 0x003007, 0x003021, 0x003029, 0x003031, 0x003035, 0x003038, + 0x00303c, 0x003041, 0x003096, 0x00309d, 0x00309f, 0x0030a1, 0x0030fa, 0x0030fc, 0x0030ff, 0x003105, 0x00312f, 0x003131, 0x00318e, 0x0031a0, 0x0031bf, 0x0031f0, 0x0031ff, + 0x003400, 0x004dbf, 0x004e00, 0x00a48c, 0x00a4d0, 0x00a4fd, 0x00a500, 0x00a60c, 0x00a610, 0x00a61f, 0x00a62a, 0x00a62b, 0x00a640, 0x00a66e, 0x00a67f, 0x00a69d, 0x00a6a0, + 0x00a6ef, 0x00a717, 0x00a71f, 0x00a722, 0x00a788, 0x00a78b, 0x00a7ca, 0x00a7d0, 0x00a7d1, 0x00a7d3, 0x00a7d3, 0x00a7d5, 0x00a7d9, 0x00a7f2, 0x00a801, 0x00a803, 0x00a805, 0x00a807, 0x00a80a, 0x00a80c, 0x00a822, 0x00a840, 0x00a873, 0x00a882, 0x00a8b3, 0x00a8f2, 0x00a8f7, 0x00a8fb, 0x00a8fb, 0x00a8fd, 0x00a8fe, 0x00a90a, 0x00a925, 0x00a930, 0x00a946, 0x00a960, 0x00a97c, 0x00a984, 0x00a9b2, 0x00a9cf, 0x00a9cf, 0x00a9e0, 0x00a9e4, 0x00a9e6, 0x00a9ef, 0x00a9fa, 0x00a9fe, 0x00aa00, 0x00aa28, 0x00aa40, 0x00aa42, 0x00aa44, 0x00aa4b, 0x00aa60, 0x00aa76, 0x00aa7a, 0x00aa7a, 0x00aa7e, 0x00aaaf, 0x00aab1, 0x00aab1, 0x00aab5, 0x00aab6, 0x00aab9, 0x00aabd, 0x00aac0, 0x00aac0, 0x00aac2, @@ -2518,33 +2569,36 @@ private static void populateXIDS() { 0x00ffc2, 0x00ffc7, 0x00ffca, 0x00ffcf, 0x00ffd2, 0x00ffd7, 0x00ffda, 0x00ffdc, 0x010000, 0x01000b, 0x01000d, 0x010026, 0x010028, 0x01003a, 0x01003c, 0x01003d, 0x01003f, 0x01004d, 0x010050, 0x01005d, 0x010080, 0x0100fa, 0x010140, 0x010174, 0x010280, 0x01029c, 0x0102a0, 0x0102d0, 0x010300, 0x01031f, 0x01032d, 0x01034a, 0x010350, 0x010375, 0x010380, 0x01039d, 0x0103a0, 0x0103c3, 0x0103c8, 0x0103cf, 0x0103d1, 0x0103d5, 0x010400, 0x01049d, 0x0104b0, 0x0104d3, 0x0104d8, 0x0104fb, 0x010500, 0x010527, 0x010530, - 0x010563, 0x010600, 0x010736, 0x010740, 0x010755, 0x010760, 0x010767, 0x010800, 0x010805, 0x010808, 0x010808, 0x01080a, 0x010835, 0x010837, 0x010838, 0x01083c, 0x01083c, - 0x01083f, 0x010855, 0x010860, 0x010876, 0x010880, 0x01089e, 0x0108e0, 0x0108f2, 0x0108f4, 0x0108f5, 0x010900, 0x010915, 0x010920, 0x010939, 0x010980, 0x0109b7, 0x0109be, - 0x0109bf, 0x010a00, 0x010a00, 0x010a10, 0x010a13, 0x010a15, 0x010a17, 0x010a19, 0x010a35, 0x010a60, 0x010a7c, 0x010a80, 0x010a9c, 0x010ac0, 0x010ac7, 0x010ac9, 0x010ae4, - 0x010b00, 0x010b35, 0x010b40, 0x010b55, 0x010b60, 0x010b72, 0x010b80, 0x010b91, 0x010c00, 0x010c48, 0x010c80, 0x010cb2, 0x010cc0, 0x010cf2, 0x010d00, 0x010d23, 0x010e80, - 0x010ea9, 0x010eb0, 0x010eb1, 0x010f00, 0x010f1c, 0x010f27, 0x010f27, 0x010f30, 0x010f45, 0x010fb0, 0x010fc4, 0x010fe0, 0x010ff6, 0x011003, 0x011037, 0x011083, 0x0110af, - 0x0110d0, 0x0110e8, 0x011103, 0x011126, 0x011144, 0x011144, 0x011147, 0x011147, 0x011150, 0x011172, 0x011176, 0x011176, 0x011183, 0x0111b2, 0x0111c1, 0x0111c4, 0x0111da, - 0x0111da, 0x0111dc, 0x0111dc, 0x011200, 0x011211, 0x011213, 0x01122b, 0x011280, 0x011286, 0x011288, 0x011288, 0x01128a, 0x01128d, 0x01128f, 0x01129d, 0x01129f, 0x0112a8, - 0x0112b0, 0x0112de, 0x011305, 0x01130c, 0x01130f, 0x011310, 0x011313, 0x011328, 0x01132a, 0x011330, 0x011332, 0x011333, 0x011335, 0x011339, 0x01133d, 0x01133d, 0x011350, - 0x011350, 0x01135d, 0x011361, 0x011400, 0x011434, 0x011447, 0x01144a, 0x01145f, 0x011461, 0x011480, 0x0114af, 0x0114c4, 0x0114c5, 0x0114c7, 0x0114c7, 0x011580, 0x0115ae, - 0x0115d8, 0x0115db, 0x011600, 0x01162f, 0x011644, 0x011644, 0x011680, 0x0116aa, 0x0116b8, 0x0116b8, 0x011700, 0x01171a, 0x011800, 0x01182b, 0x0118a0, 0x0118df, 0x0118ff, - 0x011906, 0x011909, 0x011909, 0x01190c, 0x011913, 0x011915, 0x011916, 0x011918, 0x01192f, 0x01193f, 0x01193f, 0x011941, 0x011941, 0x0119a0, 0x0119a7, 0x0119aa, 0x0119d0, - 0x0119e1, 0x0119e1, 0x0119e3, 0x0119e3, 0x011a00, 0x011a00, 0x011a0b, 0x011a32, 0x011a3a, 0x011a3a, 0x011a50, 0x011a50, 0x011a5c, 0x011a89, 0x011a9d, 0x011a9d, 0x011ac0, - 0x011af8, 0x011c00, 0x011c08, 0x011c0a, 0x011c2e, 0x011c40, 0x011c40, 0x011c72, 0x011c8f, 0x011d00, 0x011d06, 0x011d08, 0x011d09, 0x011d0b, 0x011d30, 0x011d46, 0x011d46, - 0x011d60, 0x011d65, 0x011d67, 0x011d68, 0x011d6a, 0x011d89, 0x011d98, 0x011d98, 0x011ee0, 0x011ef2, 0x011fb0, 0x011fb0, 0x012000, 0x012399, 0x012400, 0x01246e, 0x012480, - 0x012543, 0x013000, 0x01342e, 0x014400, 0x014646, 0x016800, 0x016a38, 0x016a40, 0x016a5e, 0x016ad0, 0x016aed, 0x016b00, 0x016b2f, 0x016b40, 0x016b43, 0x016b63, 0x016b77, + 0x010563, 0x010570, 0x01057a, 0x01057c, 0x01058a, 0x01058c, 0x010592, 0x010594, 0x010595, 0x010597, 0x0105a1, 0x0105a3, 0x0105b1, 0x0105b3, 0x0105b9, 0x0105bb, 0x0105bc, + 0x010600, 0x010736, 0x010740, 0x010755, 0x010760, 0x010767, 0x010780, 0x010785, 0x010787, 0x0107b0, 0x0107b2, 0x0107ba, 0x010800, 0x010805, 0x010808, 0x010808, 0x01080a, + 0x010835, 0x010837, 0x010838, 0x01083c, 0x01083c, 0x01083f, 0x010855, 0x010860, 0x010876, 0x010880, 0x01089e, 0x0108e0, 0x0108f2, 0x0108f4, 0x0108f5, 0x010900, 0x010915, + 0x010920, 0x010939, 0x010980, 0x0109b7, 0x0109be, 0x0109bf, 0x010a00, 0x010a00, 0x010a10, 0x010a13, 0x010a15, 0x010a17, 0x010a19, 0x010a35, 0x010a60, 0x010a7c, 0x010a80, + 0x010a9c, 0x010ac0, 0x010ac7, 0x010ac9, 0x010ae4, 0x010b00, 0x010b35, 0x010b40, 0x010b55, 0x010b60, 0x010b72, 0x010b80, 0x010b91, 0x010c00, 0x010c48, 0x010c80, 0x010cb2, + 0x010cc0, 0x010cf2, 0x010d00, 0x010d23, 0x010e80, 0x010ea9, 0x010eb0, 0x010eb1, 0x010f00, 0x010f1c, 0x010f27, 0x010f27, 0x010f30, 0x010f45, 0x010f70, 0x010f81, 0x010fb0, + 0x010fc4, 0x010fe0, 0x010ff6, 0x011003, 0x011037, 0x011071, 0x011072, 0x011075, 0x011075, 0x011083, 0x0110af, 0x0110d0, 0x0110e8, 0x011103, 0x011126, 0x011144, 0x011144, + 0x011147, 0x011147, 0x011150, 0x011172, 0x011176, 0x011176, 0x011183, 0x0111b2, 0x0111c1, 0x0111c4, 0x0111da, 0x0111da, 0x0111dc, 0x0111dc, 0x011200, 0x011211, 0x011213, + 0x01122b, 0x011280, 0x011286, 0x011288, 0x011288, 0x01128a, 0x01128d, 0x01128f, 0x01129d, 0x01129f, 0x0112a8, 0x0112b0, 0x0112de, 0x011305, 0x01130c, 0x01130f, 0x011310, + 0x011313, 0x011328, 0x01132a, 0x011330, 0x011332, 0x011333, 0x011335, 0x011339, 0x01133d, 0x01133d, 0x011350, 0x011350, 0x01135d, 0x011361, 0x011400, 0x011434, 0x011447, + 0x01144a, 0x01145f, 0x011461, 0x011480, 0x0114af, 0x0114c4, 0x0114c5, 0x0114c7, 0x0114c7, 0x011580, 0x0115ae, 0x0115d8, 0x0115db, 0x011600, 0x01162f, 0x011644, 0x011644, + 0x011680, 0x0116aa, 0x0116b8, 0x0116b8, 0x011700, 0x01171a, 0x011740, 0x011746, 0x011800, 0x01182b, 0x0118a0, 0x0118df, 0x0118ff, 0x011906, 0x011909, 0x011909, 0x01190c, + 0x011913, 0x011915, 0x011916, 0x011918, 0x01192f, 0x01193f, 0x01193f, 0x011941, 0x011941, 0x0119a0, 0x0119a7, 0x0119aa, 0x0119d0, 0x0119e1, 0x0119e1, 0x0119e3, 0x0119e3, + 0x011a00, 0x011a00, 0x011a0b, 0x011a32, 0x011a3a, 0x011a3a, 0x011a50, 0x011a50, 0x011a5c, 0x011a89, 0x011a9d, 0x011a9d, 0x011ab0, 0x011af8, 0x011c00, 0x011c08, 0x011c0a, + 0x011c2e, 0x011c40, 0x011c40, 0x011c72, 0x011c8f, 0x011d00, 0x011d06, 0x011d08, 0x011d09, 0x011d0b, 0x011d30, 0x011d46, 0x011d46, 0x011d60, 0x011d65, 0x011d67, 0x011d68, + 0x011d6a, 0x011d89, 0x011d98, 0x011d98, 0x011ee0, 0x011ef2, 0x011fb0, 0x011fb0, 0x012000, 0x012399, 0x012400, 0x01246e, 0x012480, 0x012543, 0x012f90, 0x012ff0, 0x013000, + 0x01342e, 0x014400, 0x014646, 0x016800, 0x016a38, 0x016a40, 0x016a5e, 0x016a70, 0x016abe, 0x016ad0, 0x016aed, 0x016b00, 0x016b2f, 0x016b40, 0x016b43, 0x016b63, 0x016b77, 0x016b7d, 0x016b8f, 0x016e40, 0x016e7f, 0x016f00, 0x016f4a, 0x016f50, 0x016f50, 0x016f93, 0x016f9f, 0x016fe0, 0x016fe1, 0x016fe3, 0x016fe3, 0x017000, 0x0187f7, 0x018800, - 0x018cd5, 0x018d00, 0x018d08, 0x01b000, 0x01b11e, 0x01b150, 0x01b152, 0x01b164, 0x01b167, 0x01b170, 0x01b2fb, 0x01bc00, 0x01bc6a, 0x01bc70, 0x01bc7c, 0x01bc80, 0x01bc88, - 0x01bc90, 0x01bc99, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, - 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, - 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d6c0, 0x01d6c2, 0x01d6da, 0x01d6dc, 0x01d6fa, 0x01d6fc, 0x01d714, 0x01d716, 0x01d734, 0x01d736, - 0x01d74e, 0x01d750, 0x01d76e, 0x01d770, 0x01d788, 0x01d78a, 0x01d7a8, 0x01d7aa, 0x01d7c2, 0x01d7c4, 0x01d7cb, 0x01e100, 0x01e12c, 0x01e137, 0x01e13d, 0x01e14e, 0x01e14e, - 0x01e2c0, 0x01e2eb, 0x01e800, 0x01e8c4, 0x01e900, 0x01e943, 0x01e94b, 0x01e94b, 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, - 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, 0x01ee39, 0x01ee3b, 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, - 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, 0x01ee57, 0x01ee57, 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, - 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, 0x01ee72, 0x01ee74, 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, 0x01ee80, 0x01ee89, 0x01ee8b, 0x01ee9b, - 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, 0x020000, 0x02a6dd, 0x02a700, 0x02b734, 0x02b740, 0x02b81d, 0x02b820, 0x02cea1, 0x02ceb0, 0x02ebe0, 0x02f800, - 0x02fa1d, 0x030000, 0x03134a)); + 0x018cd5, 0x018d00, 0x018d08, 0x01aff0, 0x01aff3, 0x01aff5, 0x01affb, 0x01affd, 0x01affe, 0x01b000, 0x01b122, 0x01b150, 0x01b152, 0x01b164, 0x01b167, 0x01b170, 0x01b2fb, + 0x01bc00, 0x01bc6a, 0x01bc70, 0x01bc7c, 0x01bc80, 0x01bc88, 0x01bc90, 0x01bc99, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, + 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, + 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d6c0, 0x01d6c2, 0x01d6da, 0x01d6dc, + 0x01d6fa, 0x01d6fc, 0x01d714, 0x01d716, 0x01d734, 0x01d736, 0x01d74e, 0x01d750, 0x01d76e, 0x01d770, 0x01d788, 0x01d78a, 0x01d7a8, 0x01d7aa, 0x01d7c2, 0x01d7c4, 0x01d7cb, + 0x01df00, 0x01df1e, 0x01e100, 0x01e12c, 0x01e137, 0x01e13d, 0x01e14e, 0x01e14e, 0x01e290, 0x01e2ad, 0x01e2c0, 0x01e2eb, 0x01e7e0, 0x01e7e6, 0x01e7e8, 0x01e7eb, 0x01e7ed, + 0x01e7ee, 0x01e7f0, 0x01e7fe, 0x01e800, 0x01e8c4, 0x01e900, 0x01e943, 0x01e94b, 0x01e94b, 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, + 0x01ee27, 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, 0x01ee39, 0x01ee3b, 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, + 0x01ee4b, 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, 0x01ee57, 0x01ee57, 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, + 0x01ee61, 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, 0x01ee72, 0x01ee74, 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, 0x01ee80, 0x01ee89, 0x01ee8b, + 0x01ee9b, 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, 0x020000, 0x02a6df, 0x02a700, 0x02b738, 0x02b740, 0x02b81d, 0x02b820, 0x02cea1, 0x02ceb0, 0x02ebe0, + 0x02f800, 0x02fa1d, 0x030000, 0x03134a)); } private static void populateGC_CC() { @@ -2553,27 +2607,27 @@ private static void populateGC_CC() { private static void populateGC_CF() { SET_ENCODINGS.put("gc=Cf", - CodePointSet.createNoDedup(0x0000ad, 0x0000ad, 0x000600, 0x000605, 0x00061c, 0x00061c, 0x0006dd, 0x0006dd, 0x00070f, 0x00070f, 0x0008e2, 0x0008e2, 0x00180e, 0x00180e, 0x00200b, - 0x00200f, 0x00202a, 0x00202e, 0x002060, 0x002064, 0x002066, 0x00206f, 0x00feff, 0x00feff, 0x00fff9, 0x00fffb, 0x0110bd, 0x0110bd, 0x0110cd, 0x0110cd, 0x013430, - 0x013438, 0x01bca0, 0x01bca3, 0x01d173, 0x01d17a, 0x0e0001, 0x0e0001, 0x0e0020, 0x0e007f)); + CodePointSet.createNoDedup(0x0000ad, 0x0000ad, 0x000600, 0x000605, 0x00061c, 0x00061c, 0x0006dd, 0x0006dd, 0x00070f, 0x00070f, 0x000890, 0x000891, 0x0008e2, 0x0008e2, 0x00180e, + 0x00180e, 0x00200b, 0x00200f, 0x00202a, 0x00202e, 0x002060, 0x002064, 0x002066, 0x00206f, 0x00feff, 0x00feff, 0x00fff9, 0x00fffb, 0x0110bd, 0x0110bd, 0x0110cd, + 0x0110cd, 0x013430, 0x013438, 0x01bca0, 0x01bca3, 0x01d173, 0x01d17a, 0x0e0001, 0x0e0001, 0x0e0020, 0x0e007f)); } private static void populateGC_CN() { SET_ENCODINGS.put("gc=Cn", CodePointSet.createNoDedup(0x000378, 0x000379, 0x000380, 0x000383, 0x00038b, 0x00038b, 0x00038d, 0x00038d, 0x0003a2, 0x0003a2, 0x000530, 0x000530, 0x000557, - 0x000558, 0x00058b, 0x00058c, 0x000590, 0x000590, 0x0005c8, 0x0005cf, 0x0005eb, 0x0005ee, 0x0005f5, 0x0005ff, 0x00061d, 0x00061d, 0x00070e, 0x00070e, 0x00074b, 0x00074c, - 0x0007b2, 0x0007bf, 0x0007fb, 0x0007fc, 0x00082e, 0x00082f, 0x00083f, 0x00083f, 0x00085c, 0x00085d, 0x00085f, 0x00085f, 0x00086b, 0x00089f, 0x0008b5, 0x0008b5, 0x0008c8, - 0x0008d2, 0x000984, 0x000984, 0x00098d, 0x00098e, 0x000991, 0x000992, 0x0009a9, 0x0009a9, 0x0009b1, 0x0009b1, 0x0009b3, 0x0009b5, 0x0009ba, 0x0009bb, 0x0009c5, 0x0009c6, - 0x0009c9, 0x0009ca, 0x0009cf, 0x0009d6, 0x0009d8, 0x0009db, 0x0009de, 0x0009de, 0x0009e4, 0x0009e5, 0x0009ff, 0x000a00, 0x000a04, 0x000a04, 0x000a0b, 0x000a0e, 0x000a11, - 0x000a12, 0x000a29, 0x000a29, 0x000a31, 0x000a31, 0x000a34, 0x000a34, 0x000a37, 0x000a37, 0x000a3a, 0x000a3b, 0x000a3d, 0x000a3d, 0x000a43, 0x000a46, 0x000a49, 0x000a4a, - 0x000a4e, 0x000a50, 0x000a52, 0x000a58, 0x000a5d, 0x000a5d, 0x000a5f, 0x000a65, 0x000a77, 0x000a80, 0x000a84, 0x000a84, 0x000a8e, 0x000a8e, 0x000a92, 0x000a92, 0x000aa9, - 0x000aa9, 0x000ab1, 0x000ab1, 0x000ab4, 0x000ab4, 0x000aba, 0x000abb, 0x000ac6, 0x000ac6, 0x000aca, 0x000aca, 0x000ace, 0x000acf, 0x000ad1, 0x000adf, 0x000ae4, 0x000ae5, - 0x000af2, 0x000af8, 0x000b00, 0x000b00, 0x000b04, 0x000b04, 0x000b0d, 0x000b0e, 0x000b11, 0x000b12, 0x000b29, 0x000b29, 0x000b31, 0x000b31, 0x000b34, 0x000b34, 0x000b3a, - 0x000b3b, 0x000b45, 0x000b46, 0x000b49, 0x000b4a, 0x000b4e, 0x000b54, 0x000b58, 0x000b5b, 0x000b5e, 0x000b5e, 0x000b64, 0x000b65, 0x000b78, 0x000b81, 0x000b84, 0x000b84, - 0x000b8b, 0x000b8d, 0x000b91, 0x000b91, 0x000b96, 0x000b98, 0x000b9b, 0x000b9b, 0x000b9d, 0x000b9d, 0x000ba0, 0x000ba2, 0x000ba5, 0x000ba7, 0x000bab, 0x000bad, 0x000bba, - 0x000bbd, 0x000bc3, 0x000bc5, 0x000bc9, 0x000bc9, 0x000bce, 0x000bcf, 0x000bd1, 0x000bd6, 0x000bd8, 0x000be5, 0x000bfb, 0x000bff, 0x000c0d, 0x000c0d, 0x000c11, 0x000c11, - 0x000c29, 0x000c29, 0x000c3a, 0x000c3c, 0x000c45, 0x000c45, 0x000c49, 0x000c49, 0x000c4e, 0x000c54, 0x000c57, 0x000c57, 0x000c5b, 0x000c5f, 0x000c64, 0x000c65, 0x000c70, + 0x000558, 0x00058b, 0x00058c, 0x000590, 0x000590, 0x0005c8, 0x0005cf, 0x0005eb, 0x0005ee, 0x0005f5, 0x0005ff, 0x00070e, 0x00070e, 0x00074b, 0x00074c, 0x0007b2, 0x0007bf, + 0x0007fb, 0x0007fc, 0x00082e, 0x00082f, 0x00083f, 0x00083f, 0x00085c, 0x00085d, 0x00085f, 0x00085f, 0x00086b, 0x00086f, 0x00088f, 0x00088f, 0x000892, 0x000897, 0x000984, + 0x000984, 0x00098d, 0x00098e, 0x000991, 0x000992, 0x0009a9, 0x0009a9, 0x0009b1, 0x0009b1, 0x0009b3, 0x0009b5, 0x0009ba, 0x0009bb, 0x0009c5, 0x0009c6, 0x0009c9, 0x0009ca, + 0x0009cf, 0x0009d6, 0x0009d8, 0x0009db, 0x0009de, 0x0009de, 0x0009e4, 0x0009e5, 0x0009ff, 0x000a00, 0x000a04, 0x000a04, 0x000a0b, 0x000a0e, 0x000a11, 0x000a12, 0x000a29, + 0x000a29, 0x000a31, 0x000a31, 0x000a34, 0x000a34, 0x000a37, 0x000a37, 0x000a3a, 0x000a3b, 0x000a3d, 0x000a3d, 0x000a43, 0x000a46, 0x000a49, 0x000a4a, 0x000a4e, 0x000a50, + 0x000a52, 0x000a58, 0x000a5d, 0x000a5d, 0x000a5f, 0x000a65, 0x000a77, 0x000a80, 0x000a84, 0x000a84, 0x000a8e, 0x000a8e, 0x000a92, 0x000a92, 0x000aa9, 0x000aa9, 0x000ab1, + 0x000ab1, 0x000ab4, 0x000ab4, 0x000aba, 0x000abb, 0x000ac6, 0x000ac6, 0x000aca, 0x000aca, 0x000ace, 0x000acf, 0x000ad1, 0x000adf, 0x000ae4, 0x000ae5, 0x000af2, 0x000af8, + 0x000b00, 0x000b00, 0x000b04, 0x000b04, 0x000b0d, 0x000b0e, 0x000b11, 0x000b12, 0x000b29, 0x000b29, 0x000b31, 0x000b31, 0x000b34, 0x000b34, 0x000b3a, 0x000b3b, 0x000b45, + 0x000b46, 0x000b49, 0x000b4a, 0x000b4e, 0x000b54, 0x000b58, 0x000b5b, 0x000b5e, 0x000b5e, 0x000b64, 0x000b65, 0x000b78, 0x000b81, 0x000b84, 0x000b84, 0x000b8b, 0x000b8d, + 0x000b91, 0x000b91, 0x000b96, 0x000b98, 0x000b9b, 0x000b9b, 0x000b9d, 0x000b9d, 0x000ba0, 0x000ba2, 0x000ba5, 0x000ba7, 0x000bab, 0x000bad, 0x000bba, 0x000bbd, 0x000bc3, + 0x000bc5, 0x000bc9, 0x000bc9, 0x000bce, 0x000bcf, 0x000bd1, 0x000bd6, 0x000bd8, 0x000be5, 0x000bfb, 0x000bff, 0x000c0d, 0x000c0d, 0x000c11, 0x000c11, 0x000c29, 0x000c29, + 0x000c3a, 0x000c3b, 0x000c45, 0x000c45, 0x000c49, 0x000c49, 0x000c4e, 0x000c54, 0x000c57, 0x000c57, 0x000c5b, 0x000c5c, 0x000c5e, 0x000c5f, 0x000c64, 0x000c65, 0x000c70, 0x000c76, 0x000c8d, 0x000c8d, 0x000c91, 0x000c91, 0x000ca9, 0x000ca9, 0x000cb4, 0x000cb4, 0x000cba, 0x000cbb, 0x000cc5, 0x000cc5, 0x000cc9, 0x000cc9, 0x000cce, 0x000cd4, - 0x000cd7, 0x000cdd, 0x000cdf, 0x000cdf, 0x000ce4, 0x000ce5, 0x000cf0, 0x000cf0, 0x000cf3, 0x000cff, 0x000d0d, 0x000d0d, 0x000d11, 0x000d11, 0x000d45, 0x000d45, 0x000d49, + 0x000cd7, 0x000cdc, 0x000cdf, 0x000cdf, 0x000ce4, 0x000ce5, 0x000cf0, 0x000cf0, 0x000cf3, 0x000cff, 0x000d0d, 0x000d0d, 0x000d11, 0x000d11, 0x000d45, 0x000d45, 0x000d49, 0x000d49, 0x000d50, 0x000d53, 0x000d64, 0x000d65, 0x000d80, 0x000d80, 0x000d84, 0x000d84, 0x000d97, 0x000d99, 0x000db2, 0x000db2, 0x000dbc, 0x000dbc, 0x000dbe, 0x000dbf, 0x000dc7, 0x000dc9, 0x000dcb, 0x000dce, 0x000dd5, 0x000dd5, 0x000dd7, 0x000dd7, 0x000de0, 0x000de5, 0x000df0, 0x000df1, 0x000df5, 0x000e00, 0x000e3b, 0x000e3e, 0x000e5c, 0x000e80, 0x000e83, 0x000e83, 0x000e85, 0x000e85, 0x000e8b, 0x000e8b, 0x000ea4, 0x000ea4, 0x000ea6, 0x000ea6, 0x000ebe, 0x000ebf, 0x000ec5, 0x000ec5, 0x000ec7, 0x000ec7, @@ -2581,64 +2635,67 @@ private static void populateGC_CN() { 0x000fff, 0x0010c6, 0x0010c6, 0x0010c8, 0x0010cc, 0x0010ce, 0x0010cf, 0x001249, 0x001249, 0x00124e, 0x00124f, 0x001257, 0x001257, 0x001259, 0x001259, 0x00125e, 0x00125f, 0x001289, 0x001289, 0x00128e, 0x00128f, 0x0012b1, 0x0012b1, 0x0012b6, 0x0012b7, 0x0012bf, 0x0012bf, 0x0012c1, 0x0012c1, 0x0012c6, 0x0012c7, 0x0012d7, 0x0012d7, 0x001311, 0x001311, 0x001316, 0x001317, 0x00135b, 0x00135c, 0x00137d, 0x00137f, 0x00139a, 0x00139f, 0x0013f6, 0x0013f7, 0x0013fe, 0x0013ff, 0x00169d, 0x00169f, 0x0016f9, 0x0016ff, - 0x00170d, 0x00170d, 0x001715, 0x00171f, 0x001737, 0x00173f, 0x001754, 0x00175f, 0x00176d, 0x00176d, 0x001771, 0x001771, 0x001774, 0x00177f, 0x0017de, 0x0017df, 0x0017ea, - 0x0017ef, 0x0017fa, 0x0017ff, 0x00180f, 0x00180f, 0x00181a, 0x00181f, 0x001879, 0x00187f, 0x0018ab, 0x0018af, 0x0018f6, 0x0018ff, 0x00191f, 0x00191f, 0x00192c, 0x00192f, - 0x00193c, 0x00193f, 0x001941, 0x001943, 0x00196e, 0x00196f, 0x001975, 0x00197f, 0x0019ac, 0x0019af, 0x0019ca, 0x0019cf, 0x0019db, 0x0019dd, 0x001a1c, 0x001a1d, 0x001a5f, - 0x001a5f, 0x001a7d, 0x001a7e, 0x001a8a, 0x001a8f, 0x001a9a, 0x001a9f, 0x001aae, 0x001aaf, 0x001ac1, 0x001aff, 0x001b4c, 0x001b4f, 0x001b7d, 0x001b7f, 0x001bf4, 0x001bfb, - 0x001c38, 0x001c3a, 0x001c4a, 0x001c4c, 0x001c89, 0x001c8f, 0x001cbb, 0x001cbc, 0x001cc8, 0x001ccf, 0x001cfb, 0x001cff, 0x001dfa, 0x001dfa, 0x001f16, 0x001f17, 0x001f1e, - 0x001f1f, 0x001f46, 0x001f47, 0x001f4e, 0x001f4f, 0x001f58, 0x001f58, 0x001f5a, 0x001f5a, 0x001f5c, 0x001f5c, 0x001f5e, 0x001f5e, 0x001f7e, 0x001f7f, 0x001fb5, 0x001fb5, - 0x001fc5, 0x001fc5, 0x001fd4, 0x001fd5, 0x001fdc, 0x001fdc, 0x001ff0, 0x001ff1, 0x001ff5, 0x001ff5, 0x001fff, 0x001fff, 0x002065, 0x002065, 0x002072, 0x002073, 0x00208f, - 0x00208f, 0x00209d, 0x00209f, 0x0020c0, 0x0020cf, 0x0020f1, 0x0020ff, 0x00218c, 0x00218f, 0x002427, 0x00243f, 0x00244b, 0x00245f, 0x002b74, 0x002b75, 0x002b96, 0x002b96, - 0x002c2f, 0x002c2f, 0x002c5f, 0x002c5f, 0x002cf4, 0x002cf8, 0x002d26, 0x002d26, 0x002d28, 0x002d2c, 0x002d2e, 0x002d2f, 0x002d68, 0x002d6e, 0x002d71, 0x002d7e, 0x002d97, - 0x002d9f, 0x002da7, 0x002da7, 0x002daf, 0x002daf, 0x002db7, 0x002db7, 0x002dbf, 0x002dbf, 0x002dc7, 0x002dc7, 0x002dcf, 0x002dcf, 0x002dd7, 0x002dd7, 0x002ddf, 0x002ddf, - 0x002e53, 0x002e7f, 0x002e9a, 0x002e9a, 0x002ef4, 0x002eff, 0x002fd6, 0x002fef, 0x002ffc, 0x002fff, 0x003040, 0x003040, 0x003097, 0x003098, 0x003100, 0x003104, 0x003130, - 0x003130, 0x00318f, 0x00318f, 0x0031e4, 0x0031ef, 0x00321f, 0x00321f, 0x009ffd, 0x009fff, 0x00a48d, 0x00a48f, 0x00a4c7, 0x00a4cf, 0x00a62c, 0x00a63f, 0x00a6f8, 0x00a6ff, - 0x00a7c0, 0x00a7c1, 0x00a7cb, 0x00a7f4, 0x00a82d, 0x00a82f, 0x00a83a, 0x00a83f, 0x00a878, 0x00a87f, 0x00a8c6, 0x00a8cd, 0x00a8da, 0x00a8df, 0x00a954, 0x00a95e, 0x00a97d, - 0x00a97f, 0x00a9ce, 0x00a9ce, 0x00a9da, 0x00a9dd, 0x00a9ff, 0x00a9ff, 0x00aa37, 0x00aa3f, 0x00aa4e, 0x00aa4f, 0x00aa5a, 0x00aa5b, 0x00aac3, 0x00aada, 0x00aaf7, 0x00ab00, - 0x00ab07, 0x00ab08, 0x00ab0f, 0x00ab10, 0x00ab17, 0x00ab1f, 0x00ab27, 0x00ab27, 0x00ab2f, 0x00ab2f, 0x00ab6c, 0x00ab6f, 0x00abee, 0x00abef, 0x00abfa, 0x00abff, 0x00d7a4, - 0x00d7af, 0x00d7c7, 0x00d7ca, 0x00d7fc, 0x00d7ff, 0x00fa6e, 0x00fa6f, 0x00fada, 0x00faff, 0x00fb07, 0x00fb12, 0x00fb18, 0x00fb1c, 0x00fb37, 0x00fb37, 0x00fb3d, 0x00fb3d, - 0x00fb3f, 0x00fb3f, 0x00fb42, 0x00fb42, 0x00fb45, 0x00fb45, 0x00fbc2, 0x00fbd2, 0x00fd40, 0x00fd4f, 0x00fd90, 0x00fd91, 0x00fdc8, 0x00fdef, 0x00fdfe, 0x00fdff, 0x00fe1a, - 0x00fe1f, 0x00fe53, 0x00fe53, 0x00fe67, 0x00fe67, 0x00fe6c, 0x00fe6f, 0x00fe75, 0x00fe75, 0x00fefd, 0x00fefe, 0x00ff00, 0x00ff00, 0x00ffbf, 0x00ffc1, 0x00ffc8, 0x00ffc9, - 0x00ffd0, 0x00ffd1, 0x00ffd8, 0x00ffd9, 0x00ffdd, 0x00ffdf, 0x00ffe7, 0x00ffe7, 0x00ffef, 0x00fff8, 0x00fffe, 0x00ffff, 0x01000c, 0x01000c, 0x010027, 0x010027, 0x01003b, - 0x01003b, 0x01003e, 0x01003e, 0x01004e, 0x01004f, 0x01005e, 0x01007f, 0x0100fb, 0x0100ff, 0x010103, 0x010106, 0x010134, 0x010136, 0x01018f, 0x01018f, 0x01019d, 0x01019f, - 0x0101a1, 0x0101cf, 0x0101fe, 0x01027f, 0x01029d, 0x01029f, 0x0102d1, 0x0102df, 0x0102fc, 0x0102ff, 0x010324, 0x01032c, 0x01034b, 0x01034f, 0x01037b, 0x01037f, 0x01039e, - 0x01039e, 0x0103c4, 0x0103c7, 0x0103d6, 0x0103ff, 0x01049e, 0x01049f, 0x0104aa, 0x0104af, 0x0104d4, 0x0104d7, 0x0104fc, 0x0104ff, 0x010528, 0x01052f, 0x010564, 0x01056e, - 0x010570, 0x0105ff, 0x010737, 0x01073f, 0x010756, 0x01075f, 0x010768, 0x0107ff, 0x010806, 0x010807, 0x010809, 0x010809, 0x010836, 0x010836, 0x010839, 0x01083b, 0x01083d, - 0x01083e, 0x010856, 0x010856, 0x01089f, 0x0108a6, 0x0108b0, 0x0108df, 0x0108f3, 0x0108f3, 0x0108f6, 0x0108fa, 0x01091c, 0x01091e, 0x01093a, 0x01093e, 0x010940, 0x01097f, - 0x0109b8, 0x0109bb, 0x0109d0, 0x0109d1, 0x010a04, 0x010a04, 0x010a07, 0x010a0b, 0x010a14, 0x010a14, 0x010a18, 0x010a18, 0x010a36, 0x010a37, 0x010a3b, 0x010a3e, 0x010a49, - 0x010a4f, 0x010a59, 0x010a5f, 0x010aa0, 0x010abf, 0x010ae7, 0x010aea, 0x010af7, 0x010aff, 0x010b36, 0x010b38, 0x010b56, 0x010b57, 0x010b73, 0x010b77, 0x010b92, 0x010b98, - 0x010b9d, 0x010ba8, 0x010bb0, 0x010bff, 0x010c49, 0x010c7f, 0x010cb3, 0x010cbf, 0x010cf3, 0x010cf9, 0x010d28, 0x010d2f, 0x010d3a, 0x010e5f, 0x010e7f, 0x010e7f, 0x010eaa, - 0x010eaa, 0x010eae, 0x010eaf, 0x010eb2, 0x010eff, 0x010f28, 0x010f2f, 0x010f5a, 0x010faf, 0x010fcc, 0x010fdf, 0x010ff7, 0x010fff, 0x01104e, 0x011051, 0x011070, 0x01107e, - 0x0110c2, 0x0110cc, 0x0110ce, 0x0110cf, 0x0110e9, 0x0110ef, 0x0110fa, 0x0110ff, 0x011135, 0x011135, 0x011148, 0x01114f, 0x011177, 0x01117f, 0x0111e0, 0x0111e0, 0x0111f5, - 0x0111ff, 0x011212, 0x011212, 0x01123f, 0x01127f, 0x011287, 0x011287, 0x011289, 0x011289, 0x01128e, 0x01128e, 0x01129e, 0x01129e, 0x0112aa, 0x0112af, 0x0112eb, 0x0112ef, - 0x0112fa, 0x0112ff, 0x011304, 0x011304, 0x01130d, 0x01130e, 0x011311, 0x011312, 0x011329, 0x011329, 0x011331, 0x011331, 0x011334, 0x011334, 0x01133a, 0x01133a, 0x011345, - 0x011346, 0x011349, 0x01134a, 0x01134e, 0x01134f, 0x011351, 0x011356, 0x011358, 0x01135c, 0x011364, 0x011365, 0x01136d, 0x01136f, 0x011375, 0x0113ff, 0x01145c, 0x01145c, - 0x011462, 0x01147f, 0x0114c8, 0x0114cf, 0x0114da, 0x01157f, 0x0115b6, 0x0115b7, 0x0115de, 0x0115ff, 0x011645, 0x01164f, 0x01165a, 0x01165f, 0x01166d, 0x01167f, 0x0116b9, - 0x0116bf, 0x0116ca, 0x0116ff, 0x01171b, 0x01171c, 0x01172c, 0x01172f, 0x011740, 0x0117ff, 0x01183c, 0x01189f, 0x0118f3, 0x0118fe, 0x011907, 0x011908, 0x01190a, 0x01190b, - 0x011914, 0x011914, 0x011917, 0x011917, 0x011936, 0x011936, 0x011939, 0x01193a, 0x011947, 0x01194f, 0x01195a, 0x01199f, 0x0119a8, 0x0119a9, 0x0119d8, 0x0119d9, 0x0119e5, - 0x0119ff, 0x011a48, 0x011a4f, 0x011aa3, 0x011abf, 0x011af9, 0x011bff, 0x011c09, 0x011c09, 0x011c37, 0x011c37, 0x011c46, 0x011c4f, 0x011c6d, 0x011c6f, 0x011c90, 0x011c91, - 0x011ca8, 0x011ca8, 0x011cb7, 0x011cff, 0x011d07, 0x011d07, 0x011d0a, 0x011d0a, 0x011d37, 0x011d39, 0x011d3b, 0x011d3b, 0x011d3e, 0x011d3e, 0x011d48, 0x011d4f, 0x011d5a, - 0x011d5f, 0x011d66, 0x011d66, 0x011d69, 0x011d69, 0x011d8f, 0x011d8f, 0x011d92, 0x011d92, 0x011d99, 0x011d9f, 0x011daa, 0x011edf, 0x011ef9, 0x011faf, 0x011fb1, 0x011fbf, - 0x011ff2, 0x011ffe, 0x01239a, 0x0123ff, 0x01246f, 0x01246f, 0x012475, 0x01247f, 0x012544, 0x012fff, 0x01342f, 0x01342f, 0x013439, 0x0143ff, 0x014647, 0x0167ff, 0x016a39, - 0x016a3f, 0x016a5f, 0x016a5f, 0x016a6a, 0x016a6d, 0x016a70, 0x016acf, 0x016aee, 0x016aef, 0x016af6, 0x016aff, 0x016b46, 0x016b4f, 0x016b5a, 0x016b5a, 0x016b62, 0x016b62, - 0x016b78, 0x016b7c, 0x016b90, 0x016e3f, 0x016e9b, 0x016eff, 0x016f4b, 0x016f4e, 0x016f88, 0x016f8e, 0x016fa0, 0x016fdf, 0x016fe5, 0x016fef, 0x016ff2, 0x016fff, 0x0187f8, - 0x0187ff, 0x018cd6, 0x018cff, 0x018d09, 0x01afff, 0x01b11f, 0x01b14f, 0x01b153, 0x01b163, 0x01b168, 0x01b16f, 0x01b2fc, 0x01bbff, 0x01bc6b, 0x01bc6f, 0x01bc7d, 0x01bc7f, - 0x01bc89, 0x01bc8f, 0x01bc9a, 0x01bc9b, 0x01bca4, 0x01cfff, 0x01d0f6, 0x01d0ff, 0x01d127, 0x01d128, 0x01d1e9, 0x01d1ff, 0x01d246, 0x01d2df, 0x01d2f4, 0x01d2ff, 0x01d357, - 0x01d35f, 0x01d379, 0x01d3ff, 0x01d455, 0x01d455, 0x01d49d, 0x01d49d, 0x01d4a0, 0x01d4a1, 0x01d4a3, 0x01d4a4, 0x01d4a7, 0x01d4a8, 0x01d4ad, 0x01d4ad, 0x01d4ba, 0x01d4ba, - 0x01d4bc, 0x01d4bc, 0x01d4c4, 0x01d4c4, 0x01d506, 0x01d506, 0x01d50b, 0x01d50c, 0x01d515, 0x01d515, 0x01d51d, 0x01d51d, 0x01d53a, 0x01d53a, 0x01d53f, 0x01d53f, 0x01d545, - 0x01d545, 0x01d547, 0x01d549, 0x01d551, 0x01d551, 0x01d6a6, 0x01d6a7, 0x01d7cc, 0x01d7cd, 0x01da8c, 0x01da9a, 0x01daa0, 0x01daa0, 0x01dab0, 0x01dfff, 0x01e007, 0x01e007, - 0x01e019, 0x01e01a, 0x01e022, 0x01e022, 0x01e025, 0x01e025, 0x01e02b, 0x01e0ff, 0x01e12d, 0x01e12f, 0x01e13e, 0x01e13f, 0x01e14a, 0x01e14d, 0x01e150, 0x01e2bf, 0x01e2fa, - 0x01e2fe, 0x01e300, 0x01e7ff, 0x01e8c5, 0x01e8c6, 0x01e8d7, 0x01e8ff, 0x01e94c, 0x01e94f, 0x01e95a, 0x01e95d, 0x01e960, 0x01ec70, 0x01ecb5, 0x01ed00, 0x01ed3e, 0x01edff, - 0x01ee04, 0x01ee04, 0x01ee20, 0x01ee20, 0x01ee23, 0x01ee23, 0x01ee25, 0x01ee26, 0x01ee28, 0x01ee28, 0x01ee33, 0x01ee33, 0x01ee38, 0x01ee38, 0x01ee3a, 0x01ee3a, 0x01ee3c, - 0x01ee41, 0x01ee43, 0x01ee46, 0x01ee48, 0x01ee48, 0x01ee4a, 0x01ee4a, 0x01ee4c, 0x01ee4c, 0x01ee50, 0x01ee50, 0x01ee53, 0x01ee53, 0x01ee55, 0x01ee56, 0x01ee58, 0x01ee58, - 0x01ee5a, 0x01ee5a, 0x01ee5c, 0x01ee5c, 0x01ee5e, 0x01ee5e, 0x01ee60, 0x01ee60, 0x01ee63, 0x01ee63, 0x01ee65, 0x01ee66, 0x01ee6b, 0x01ee6b, 0x01ee73, 0x01ee73, 0x01ee78, - 0x01ee78, 0x01ee7d, 0x01ee7d, 0x01ee7f, 0x01ee7f, 0x01ee8a, 0x01ee8a, 0x01ee9c, 0x01eea0, 0x01eea4, 0x01eea4, 0x01eeaa, 0x01eeaa, 0x01eebc, 0x01eeef, 0x01eef2, 0x01efff, - 0x01f02c, 0x01f02f, 0x01f094, 0x01f09f, 0x01f0af, 0x01f0b0, 0x01f0c0, 0x01f0c0, 0x01f0d0, 0x01f0d0, 0x01f0f6, 0x01f0ff, 0x01f1ae, 0x01f1e5, 0x01f203, 0x01f20f, 0x01f23c, - 0x01f23f, 0x01f249, 0x01f24f, 0x01f252, 0x01f25f, 0x01f266, 0x01f2ff, 0x01f6d8, 0x01f6df, 0x01f6ed, 0x01f6ef, 0x01f6fd, 0x01f6ff, 0x01f774, 0x01f77f, 0x01f7d9, 0x01f7df, - 0x01f7ec, 0x01f7ff, 0x01f80c, 0x01f80f, 0x01f848, 0x01f84f, 0x01f85a, 0x01f85f, 0x01f888, 0x01f88f, 0x01f8ae, 0x01f8af, 0x01f8b2, 0x01f8ff, 0x01f979, 0x01f979, 0x01f9cc, - 0x01f9cc, 0x01fa54, 0x01fa5f, 0x01fa6e, 0x01fa6f, 0x01fa75, 0x01fa77, 0x01fa7b, 0x01fa7f, 0x01fa87, 0x01fa8f, 0x01faa9, 0x01faaf, 0x01fab7, 0x01fabf, 0x01fac3, 0x01facf, - 0x01fad7, 0x01faff, 0x01fb93, 0x01fb93, 0x01fbcb, 0x01fbef, 0x01fbfa, 0x01ffff, 0x02a6de, 0x02a6ff, 0x02b735, 0x02b73f, 0x02b81e, 0x02b81f, 0x02cea2, 0x02ceaf, 0x02ebe1, - 0x02f7ff, 0x02fa1e, 0x02ffff, 0x03134b, 0x0e0000, 0x0e0002, 0x0e001f, 0x0e0080, 0x0e00ff, 0x0e01f0, 0x0effff, 0x0ffffe, 0x0fffff, 0x10fffe, 0x10ffff)); + 0x001716, 0x00171e, 0x001737, 0x00173f, 0x001754, 0x00175f, 0x00176d, 0x00176d, 0x001771, 0x001771, 0x001774, 0x00177f, 0x0017de, 0x0017df, 0x0017ea, 0x0017ef, 0x0017fa, + 0x0017ff, 0x00181a, 0x00181f, 0x001879, 0x00187f, 0x0018ab, 0x0018af, 0x0018f6, 0x0018ff, 0x00191f, 0x00191f, 0x00192c, 0x00192f, 0x00193c, 0x00193f, 0x001941, 0x001943, + 0x00196e, 0x00196f, 0x001975, 0x00197f, 0x0019ac, 0x0019af, 0x0019ca, 0x0019cf, 0x0019db, 0x0019dd, 0x001a1c, 0x001a1d, 0x001a5f, 0x001a5f, 0x001a7d, 0x001a7e, 0x001a8a, + 0x001a8f, 0x001a9a, 0x001a9f, 0x001aae, 0x001aaf, 0x001acf, 0x001aff, 0x001b4d, 0x001b4f, 0x001b7f, 0x001b7f, 0x001bf4, 0x001bfb, 0x001c38, 0x001c3a, 0x001c4a, 0x001c4c, + 0x001c89, 0x001c8f, 0x001cbb, 0x001cbc, 0x001cc8, 0x001ccf, 0x001cfb, 0x001cff, 0x001f16, 0x001f17, 0x001f1e, 0x001f1f, 0x001f46, 0x001f47, 0x001f4e, 0x001f4f, 0x001f58, + 0x001f58, 0x001f5a, 0x001f5a, 0x001f5c, 0x001f5c, 0x001f5e, 0x001f5e, 0x001f7e, 0x001f7f, 0x001fb5, 0x001fb5, 0x001fc5, 0x001fc5, 0x001fd4, 0x001fd5, 0x001fdc, 0x001fdc, + 0x001ff0, 0x001ff1, 0x001ff5, 0x001ff5, 0x001fff, 0x001fff, 0x002065, 0x002065, 0x002072, 0x002073, 0x00208f, 0x00208f, 0x00209d, 0x00209f, 0x0020c1, 0x0020cf, 0x0020f1, + 0x0020ff, 0x00218c, 0x00218f, 0x002427, 0x00243f, 0x00244b, 0x00245f, 0x002b74, 0x002b75, 0x002b96, 0x002b96, 0x002cf4, 0x002cf8, 0x002d26, 0x002d26, 0x002d28, 0x002d2c, + 0x002d2e, 0x002d2f, 0x002d68, 0x002d6e, 0x002d71, 0x002d7e, 0x002d97, 0x002d9f, 0x002da7, 0x002da7, 0x002daf, 0x002daf, 0x002db7, 0x002db7, 0x002dbf, 0x002dbf, 0x002dc7, + 0x002dc7, 0x002dcf, 0x002dcf, 0x002dd7, 0x002dd7, 0x002ddf, 0x002ddf, 0x002e5e, 0x002e7f, 0x002e9a, 0x002e9a, 0x002ef4, 0x002eff, 0x002fd6, 0x002fef, 0x002ffc, 0x002fff, + 0x003040, 0x003040, 0x003097, 0x003098, 0x003100, 0x003104, 0x003130, 0x003130, 0x00318f, 0x00318f, 0x0031e4, 0x0031ef, 0x00321f, 0x00321f, 0x00a48d, 0x00a48f, 0x00a4c7, + 0x00a4cf, 0x00a62c, 0x00a63f, 0x00a6f8, 0x00a6ff, 0x00a7cb, 0x00a7cf, 0x00a7d2, 0x00a7d2, 0x00a7d4, 0x00a7d4, 0x00a7da, 0x00a7f1, 0x00a82d, 0x00a82f, 0x00a83a, 0x00a83f, + 0x00a878, 0x00a87f, 0x00a8c6, 0x00a8cd, 0x00a8da, 0x00a8df, 0x00a954, 0x00a95e, 0x00a97d, 0x00a97f, 0x00a9ce, 0x00a9ce, 0x00a9da, 0x00a9dd, 0x00a9ff, 0x00a9ff, 0x00aa37, + 0x00aa3f, 0x00aa4e, 0x00aa4f, 0x00aa5a, 0x00aa5b, 0x00aac3, 0x00aada, 0x00aaf7, 0x00ab00, 0x00ab07, 0x00ab08, 0x00ab0f, 0x00ab10, 0x00ab17, 0x00ab1f, 0x00ab27, 0x00ab27, + 0x00ab2f, 0x00ab2f, 0x00ab6c, 0x00ab6f, 0x00abee, 0x00abef, 0x00abfa, 0x00abff, 0x00d7a4, 0x00d7af, 0x00d7c7, 0x00d7ca, 0x00d7fc, 0x00d7ff, 0x00fa6e, 0x00fa6f, 0x00fada, + 0x00faff, 0x00fb07, 0x00fb12, 0x00fb18, 0x00fb1c, 0x00fb37, 0x00fb37, 0x00fb3d, 0x00fb3d, 0x00fb3f, 0x00fb3f, 0x00fb42, 0x00fb42, 0x00fb45, 0x00fb45, 0x00fbc3, 0x00fbd2, + 0x00fd90, 0x00fd91, 0x00fdc8, 0x00fdce, 0x00fdd0, 0x00fdef, 0x00fe1a, 0x00fe1f, 0x00fe53, 0x00fe53, 0x00fe67, 0x00fe67, 0x00fe6c, 0x00fe6f, 0x00fe75, 0x00fe75, 0x00fefd, + 0x00fefe, 0x00ff00, 0x00ff00, 0x00ffbf, 0x00ffc1, 0x00ffc8, 0x00ffc9, 0x00ffd0, 0x00ffd1, 0x00ffd8, 0x00ffd9, 0x00ffdd, 0x00ffdf, 0x00ffe7, 0x00ffe7, 0x00ffef, 0x00fff8, + 0x00fffe, 0x00ffff, 0x01000c, 0x01000c, 0x010027, 0x010027, 0x01003b, 0x01003b, 0x01003e, 0x01003e, 0x01004e, 0x01004f, 0x01005e, 0x01007f, 0x0100fb, 0x0100ff, 0x010103, + 0x010106, 0x010134, 0x010136, 0x01018f, 0x01018f, 0x01019d, 0x01019f, 0x0101a1, 0x0101cf, 0x0101fe, 0x01027f, 0x01029d, 0x01029f, 0x0102d1, 0x0102df, 0x0102fc, 0x0102ff, + 0x010324, 0x01032c, 0x01034b, 0x01034f, 0x01037b, 0x01037f, 0x01039e, 0x01039e, 0x0103c4, 0x0103c7, 0x0103d6, 0x0103ff, 0x01049e, 0x01049f, 0x0104aa, 0x0104af, 0x0104d4, + 0x0104d7, 0x0104fc, 0x0104ff, 0x010528, 0x01052f, 0x010564, 0x01056e, 0x01057b, 0x01057b, 0x01058b, 0x01058b, 0x010593, 0x010593, 0x010596, 0x010596, 0x0105a2, 0x0105a2, + 0x0105b2, 0x0105b2, 0x0105ba, 0x0105ba, 0x0105bd, 0x0105ff, 0x010737, 0x01073f, 0x010756, 0x01075f, 0x010768, 0x01077f, 0x010786, 0x010786, 0x0107b1, 0x0107b1, 0x0107bb, + 0x0107ff, 0x010806, 0x010807, 0x010809, 0x010809, 0x010836, 0x010836, 0x010839, 0x01083b, 0x01083d, 0x01083e, 0x010856, 0x010856, 0x01089f, 0x0108a6, 0x0108b0, 0x0108df, + 0x0108f3, 0x0108f3, 0x0108f6, 0x0108fa, 0x01091c, 0x01091e, 0x01093a, 0x01093e, 0x010940, 0x01097f, 0x0109b8, 0x0109bb, 0x0109d0, 0x0109d1, 0x010a04, 0x010a04, 0x010a07, + 0x010a0b, 0x010a14, 0x010a14, 0x010a18, 0x010a18, 0x010a36, 0x010a37, 0x010a3b, 0x010a3e, 0x010a49, 0x010a4f, 0x010a59, 0x010a5f, 0x010aa0, 0x010abf, 0x010ae7, 0x010aea, + 0x010af7, 0x010aff, 0x010b36, 0x010b38, 0x010b56, 0x010b57, 0x010b73, 0x010b77, 0x010b92, 0x010b98, 0x010b9d, 0x010ba8, 0x010bb0, 0x010bff, 0x010c49, 0x010c7f, 0x010cb3, + 0x010cbf, 0x010cf3, 0x010cf9, 0x010d28, 0x010d2f, 0x010d3a, 0x010e5f, 0x010e7f, 0x010e7f, 0x010eaa, 0x010eaa, 0x010eae, 0x010eaf, 0x010eb2, 0x010eff, 0x010f28, 0x010f2f, + 0x010f5a, 0x010f6f, 0x010f8a, 0x010faf, 0x010fcc, 0x010fdf, 0x010ff7, 0x010fff, 0x01104e, 0x011051, 0x011076, 0x01107e, 0x0110c3, 0x0110cc, 0x0110ce, 0x0110cf, 0x0110e9, + 0x0110ef, 0x0110fa, 0x0110ff, 0x011135, 0x011135, 0x011148, 0x01114f, 0x011177, 0x01117f, 0x0111e0, 0x0111e0, 0x0111f5, 0x0111ff, 0x011212, 0x011212, 0x01123f, 0x01127f, + 0x011287, 0x011287, 0x011289, 0x011289, 0x01128e, 0x01128e, 0x01129e, 0x01129e, 0x0112aa, 0x0112af, 0x0112eb, 0x0112ef, 0x0112fa, 0x0112ff, 0x011304, 0x011304, 0x01130d, + 0x01130e, 0x011311, 0x011312, 0x011329, 0x011329, 0x011331, 0x011331, 0x011334, 0x011334, 0x01133a, 0x01133a, 0x011345, 0x011346, 0x011349, 0x01134a, 0x01134e, 0x01134f, + 0x011351, 0x011356, 0x011358, 0x01135c, 0x011364, 0x011365, 0x01136d, 0x01136f, 0x011375, 0x0113ff, 0x01145c, 0x01145c, 0x011462, 0x01147f, 0x0114c8, 0x0114cf, 0x0114da, + 0x01157f, 0x0115b6, 0x0115b7, 0x0115de, 0x0115ff, 0x011645, 0x01164f, 0x01165a, 0x01165f, 0x01166d, 0x01167f, 0x0116ba, 0x0116bf, 0x0116ca, 0x0116ff, 0x01171b, 0x01171c, + 0x01172c, 0x01172f, 0x011747, 0x0117ff, 0x01183c, 0x01189f, 0x0118f3, 0x0118fe, 0x011907, 0x011908, 0x01190a, 0x01190b, 0x011914, 0x011914, 0x011917, 0x011917, 0x011936, + 0x011936, 0x011939, 0x01193a, 0x011947, 0x01194f, 0x01195a, 0x01199f, 0x0119a8, 0x0119a9, 0x0119d8, 0x0119d9, 0x0119e5, 0x0119ff, 0x011a48, 0x011a4f, 0x011aa3, 0x011aaf, + 0x011af9, 0x011bff, 0x011c09, 0x011c09, 0x011c37, 0x011c37, 0x011c46, 0x011c4f, 0x011c6d, 0x011c6f, 0x011c90, 0x011c91, 0x011ca8, 0x011ca8, 0x011cb7, 0x011cff, 0x011d07, + 0x011d07, 0x011d0a, 0x011d0a, 0x011d37, 0x011d39, 0x011d3b, 0x011d3b, 0x011d3e, 0x011d3e, 0x011d48, 0x011d4f, 0x011d5a, 0x011d5f, 0x011d66, 0x011d66, 0x011d69, 0x011d69, + 0x011d8f, 0x011d8f, 0x011d92, 0x011d92, 0x011d99, 0x011d9f, 0x011daa, 0x011edf, 0x011ef9, 0x011faf, 0x011fb1, 0x011fbf, 0x011ff2, 0x011ffe, 0x01239a, 0x0123ff, 0x01246f, + 0x01246f, 0x012475, 0x01247f, 0x012544, 0x012f8f, 0x012ff3, 0x012fff, 0x01342f, 0x01342f, 0x013439, 0x0143ff, 0x014647, 0x0167ff, 0x016a39, 0x016a3f, 0x016a5f, 0x016a5f, + 0x016a6a, 0x016a6d, 0x016abf, 0x016abf, 0x016aca, 0x016acf, 0x016aee, 0x016aef, 0x016af6, 0x016aff, 0x016b46, 0x016b4f, 0x016b5a, 0x016b5a, 0x016b62, 0x016b62, 0x016b78, + 0x016b7c, 0x016b90, 0x016e3f, 0x016e9b, 0x016eff, 0x016f4b, 0x016f4e, 0x016f88, 0x016f8e, 0x016fa0, 0x016fdf, 0x016fe5, 0x016fef, 0x016ff2, 0x016fff, 0x0187f8, 0x0187ff, + 0x018cd6, 0x018cff, 0x018d09, 0x01afef, 0x01aff4, 0x01aff4, 0x01affc, 0x01affc, 0x01afff, 0x01afff, 0x01b123, 0x01b14f, 0x01b153, 0x01b163, 0x01b168, 0x01b16f, 0x01b2fc, + 0x01bbff, 0x01bc6b, 0x01bc6f, 0x01bc7d, 0x01bc7f, 0x01bc89, 0x01bc8f, 0x01bc9a, 0x01bc9b, 0x01bca4, 0x01ceff, 0x01cf2e, 0x01cf2f, 0x01cf47, 0x01cf4f, 0x01cfc4, 0x01cfff, + 0x01d0f6, 0x01d0ff, 0x01d127, 0x01d128, 0x01d1eb, 0x01d1ff, 0x01d246, 0x01d2df, 0x01d2f4, 0x01d2ff, 0x01d357, 0x01d35f, 0x01d379, 0x01d3ff, 0x01d455, 0x01d455, 0x01d49d, + 0x01d49d, 0x01d4a0, 0x01d4a1, 0x01d4a3, 0x01d4a4, 0x01d4a7, 0x01d4a8, 0x01d4ad, 0x01d4ad, 0x01d4ba, 0x01d4ba, 0x01d4bc, 0x01d4bc, 0x01d4c4, 0x01d4c4, 0x01d506, 0x01d506, + 0x01d50b, 0x01d50c, 0x01d515, 0x01d515, 0x01d51d, 0x01d51d, 0x01d53a, 0x01d53a, 0x01d53f, 0x01d53f, 0x01d545, 0x01d545, 0x01d547, 0x01d549, 0x01d551, 0x01d551, 0x01d6a6, + 0x01d6a7, 0x01d7cc, 0x01d7cd, 0x01da8c, 0x01da9a, 0x01daa0, 0x01daa0, 0x01dab0, 0x01deff, 0x01df1f, 0x01dfff, 0x01e007, 0x01e007, 0x01e019, 0x01e01a, 0x01e022, 0x01e022, + 0x01e025, 0x01e025, 0x01e02b, 0x01e0ff, 0x01e12d, 0x01e12f, 0x01e13e, 0x01e13f, 0x01e14a, 0x01e14d, 0x01e150, 0x01e28f, 0x01e2af, 0x01e2bf, 0x01e2fa, 0x01e2fe, 0x01e300, + 0x01e7df, 0x01e7e7, 0x01e7e7, 0x01e7ec, 0x01e7ec, 0x01e7ef, 0x01e7ef, 0x01e7ff, 0x01e7ff, 0x01e8c5, 0x01e8c6, 0x01e8d7, 0x01e8ff, 0x01e94c, 0x01e94f, 0x01e95a, 0x01e95d, + 0x01e960, 0x01ec70, 0x01ecb5, 0x01ed00, 0x01ed3e, 0x01edff, 0x01ee04, 0x01ee04, 0x01ee20, 0x01ee20, 0x01ee23, 0x01ee23, 0x01ee25, 0x01ee26, 0x01ee28, 0x01ee28, 0x01ee33, + 0x01ee33, 0x01ee38, 0x01ee38, 0x01ee3a, 0x01ee3a, 0x01ee3c, 0x01ee41, 0x01ee43, 0x01ee46, 0x01ee48, 0x01ee48, 0x01ee4a, 0x01ee4a, 0x01ee4c, 0x01ee4c, 0x01ee50, 0x01ee50, + 0x01ee53, 0x01ee53, 0x01ee55, 0x01ee56, 0x01ee58, 0x01ee58, 0x01ee5a, 0x01ee5a, 0x01ee5c, 0x01ee5c, 0x01ee5e, 0x01ee5e, 0x01ee60, 0x01ee60, 0x01ee63, 0x01ee63, 0x01ee65, + 0x01ee66, 0x01ee6b, 0x01ee6b, 0x01ee73, 0x01ee73, 0x01ee78, 0x01ee78, 0x01ee7d, 0x01ee7d, 0x01ee7f, 0x01ee7f, 0x01ee8a, 0x01ee8a, 0x01ee9c, 0x01eea0, 0x01eea4, 0x01eea4, + 0x01eeaa, 0x01eeaa, 0x01eebc, 0x01eeef, 0x01eef2, 0x01efff, 0x01f02c, 0x01f02f, 0x01f094, 0x01f09f, 0x01f0af, 0x01f0b0, 0x01f0c0, 0x01f0c0, 0x01f0d0, 0x01f0d0, 0x01f0f6, + 0x01f0ff, 0x01f1ae, 0x01f1e5, 0x01f203, 0x01f20f, 0x01f23c, 0x01f23f, 0x01f249, 0x01f24f, 0x01f252, 0x01f25f, 0x01f266, 0x01f2ff, 0x01f6d8, 0x01f6dc, 0x01f6ed, 0x01f6ef, + 0x01f6fd, 0x01f6ff, 0x01f774, 0x01f77f, 0x01f7d9, 0x01f7df, 0x01f7ec, 0x01f7ef, 0x01f7f1, 0x01f7ff, 0x01f80c, 0x01f80f, 0x01f848, 0x01f84f, 0x01f85a, 0x01f85f, 0x01f888, + 0x01f88f, 0x01f8ae, 0x01f8af, 0x01f8b2, 0x01f8ff, 0x01fa54, 0x01fa5f, 0x01fa6e, 0x01fa6f, 0x01fa75, 0x01fa77, 0x01fa7d, 0x01fa7f, 0x01fa87, 0x01fa8f, 0x01faad, 0x01faaf, + 0x01fabb, 0x01fabf, 0x01fac6, 0x01facf, 0x01fada, 0x01fadf, 0x01fae8, 0x01faef, 0x01faf7, 0x01faff, 0x01fb93, 0x01fb93, 0x01fbcb, 0x01fbef, 0x01fbfa, 0x01ffff, 0x02a6e0, + 0x02a6ff, 0x02b739, 0x02b73f, 0x02b81e, 0x02b81f, 0x02cea2, 0x02ceaf, 0x02ebe1, 0x02f7ff, 0x02fa1e, 0x02ffff, 0x03134b, 0x0e0000, 0x0e0002, 0x0e001f, 0x0e0080, 0x0e00ff, + 0x0e01f0, 0x0effff, 0x0ffffe, 0x0fffff, 0x10fffe, 0x10ffff)); } private static void populateGC_CO() { @@ -2701,7 +2758,7 @@ private static void populateGC_LL() { 0x001f60, 0x001f67, 0x001f70, 0x001f7d, 0x001f80, 0x001f87, 0x001f90, 0x001f97, 0x001fa0, 0x001fa7, 0x001fb0, 0x001fb4, 0x001fb6, 0x001fb7, 0x001fbe, 0x001fbe, 0x001fc2, 0x001fc4, 0x001fc6, 0x001fc7, 0x001fd0, 0x001fd3, 0x001fd6, 0x001fd7, 0x001fe0, 0x001fe7, 0x001ff2, 0x001ff4, 0x001ff6, 0x001ff7, 0x00210a, 0x00210a, 0x00210e, 0x00210f, 0x002113, 0x002113, 0x00212f, 0x00212f, 0x002134, 0x002134, 0x002139, 0x002139, 0x00213c, 0x00213d, 0x002146, 0x002149, 0x00214e, 0x00214e, 0x002184, 0x002184, 0x002c30, - 0x002c5e, 0x002c61, 0x002c61, 0x002c65, 0x002c66, 0x002c68, 0x002c68, 0x002c6a, 0x002c6a, 0x002c6c, 0x002c6c, 0x002c71, 0x002c71, 0x002c73, 0x002c74, 0x002c76, 0x002c7b, + 0x002c5f, 0x002c61, 0x002c61, 0x002c65, 0x002c66, 0x002c68, 0x002c68, 0x002c6a, 0x002c6a, 0x002c6c, 0x002c6c, 0x002c71, 0x002c71, 0x002c73, 0x002c74, 0x002c76, 0x002c7b, 0x002c81, 0x002c81, 0x002c83, 0x002c83, 0x002c85, 0x002c85, 0x002c87, 0x002c87, 0x002c89, 0x002c89, 0x002c8b, 0x002c8b, 0x002c8d, 0x002c8d, 0x002c8f, 0x002c8f, 0x002c91, 0x002c91, 0x002c93, 0x002c93, 0x002c95, 0x002c95, 0x002c97, 0x002c97, 0x002c99, 0x002c99, 0x002c9b, 0x002c9b, 0x002c9d, 0x002c9d, 0x002c9f, 0x002c9f, 0x002ca1, 0x002ca1, 0x002ca3, 0x002ca3, 0x002ca5, 0x002ca5, 0x002ca7, 0x002ca7, 0x002ca9, 0x002ca9, 0x002cab, 0x002cab, 0x002cad, 0x002cad, 0x002caf, 0x002caf, 0x002cb1, 0x002cb1, 0x002cb3, @@ -2720,54 +2777,56 @@ private static void populateGC_LL() { 0x00a769, 0x00a76b, 0x00a76b, 0x00a76d, 0x00a76d, 0x00a76f, 0x00a76f, 0x00a771, 0x00a778, 0x00a77a, 0x00a77a, 0x00a77c, 0x00a77c, 0x00a77f, 0x00a77f, 0x00a781, 0x00a781, 0x00a783, 0x00a783, 0x00a785, 0x00a785, 0x00a787, 0x00a787, 0x00a78c, 0x00a78c, 0x00a78e, 0x00a78e, 0x00a791, 0x00a791, 0x00a793, 0x00a795, 0x00a797, 0x00a797, 0x00a799, 0x00a799, 0x00a79b, 0x00a79b, 0x00a79d, 0x00a79d, 0x00a79f, 0x00a79f, 0x00a7a1, 0x00a7a1, 0x00a7a3, 0x00a7a3, 0x00a7a5, 0x00a7a5, 0x00a7a7, 0x00a7a7, 0x00a7a9, 0x00a7a9, - 0x00a7af, 0x00a7af, 0x00a7b5, 0x00a7b5, 0x00a7b7, 0x00a7b7, 0x00a7b9, 0x00a7b9, 0x00a7bb, 0x00a7bb, 0x00a7bd, 0x00a7bd, 0x00a7bf, 0x00a7bf, 0x00a7c3, 0x00a7c3, 0x00a7c8, - 0x00a7c8, 0x00a7ca, 0x00a7ca, 0x00a7f6, 0x00a7f6, 0x00a7fa, 0x00a7fa, 0x00ab30, 0x00ab5a, 0x00ab60, 0x00ab68, 0x00ab70, 0x00abbf, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, - 0x00ff41, 0x00ff5a, 0x010428, 0x01044f, 0x0104d8, 0x0104fb, 0x010cc0, 0x010cf2, 0x0118c0, 0x0118df, 0x016e60, 0x016e7f, 0x01d41a, 0x01d433, 0x01d44e, 0x01d454, 0x01d456, - 0x01d467, 0x01d482, 0x01d49b, 0x01d4b6, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d4cf, 0x01d4ea, 0x01d503, 0x01d51e, 0x01d537, 0x01d552, 0x01d56b, - 0x01d586, 0x01d59f, 0x01d5ba, 0x01d5d3, 0x01d5ee, 0x01d607, 0x01d622, 0x01d63b, 0x01d656, 0x01d66f, 0x01d68a, 0x01d6a5, 0x01d6c2, 0x01d6da, 0x01d6dc, 0x01d6e1, 0x01d6fc, - 0x01d714, 0x01d716, 0x01d71b, 0x01d736, 0x01d74e, 0x01d750, 0x01d755, 0x01d770, 0x01d788, 0x01d78a, 0x01d78f, 0x01d7aa, 0x01d7c2, 0x01d7c4, 0x01d7c9, 0x01d7cb, 0x01d7cb, - 0x01e922, 0x01e943)); + 0x00a7af, 0x00a7af, 0x00a7b5, 0x00a7b5, 0x00a7b7, 0x00a7b7, 0x00a7b9, 0x00a7b9, 0x00a7bb, 0x00a7bb, 0x00a7bd, 0x00a7bd, 0x00a7bf, 0x00a7bf, 0x00a7c1, 0x00a7c1, 0x00a7c3, + 0x00a7c3, 0x00a7c8, 0x00a7c8, 0x00a7ca, 0x00a7ca, 0x00a7d1, 0x00a7d1, 0x00a7d3, 0x00a7d3, 0x00a7d5, 0x00a7d5, 0x00a7d7, 0x00a7d7, 0x00a7d9, 0x00a7d9, 0x00a7f6, 0x00a7f6, + 0x00a7fa, 0x00a7fa, 0x00ab30, 0x00ab5a, 0x00ab60, 0x00ab68, 0x00ab70, 0x00abbf, 0x00fb00, 0x00fb06, 0x00fb13, 0x00fb17, 0x00ff41, 0x00ff5a, 0x010428, 0x01044f, 0x0104d8, + 0x0104fb, 0x010597, 0x0105a1, 0x0105a3, 0x0105b1, 0x0105b3, 0x0105b9, 0x0105bb, 0x0105bc, 0x010cc0, 0x010cf2, 0x0118c0, 0x0118df, 0x016e60, 0x016e7f, 0x01d41a, 0x01d433, + 0x01d44e, 0x01d454, 0x01d456, 0x01d467, 0x01d482, 0x01d49b, 0x01d4b6, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d4cf, 0x01d4ea, 0x01d503, 0x01d51e, + 0x01d537, 0x01d552, 0x01d56b, 0x01d586, 0x01d59f, 0x01d5ba, 0x01d5d3, 0x01d5ee, 0x01d607, 0x01d622, 0x01d63b, 0x01d656, 0x01d66f, 0x01d68a, 0x01d6a5, 0x01d6c2, 0x01d6da, + 0x01d6dc, 0x01d6e1, 0x01d6fc, 0x01d714, 0x01d716, 0x01d71b, 0x01d736, 0x01d74e, 0x01d750, 0x01d755, 0x01d770, 0x01d788, 0x01d78a, 0x01d78f, 0x01d7aa, 0x01d7c2, 0x01d7c4, + 0x01d7c9, 0x01d7cb, 0x01d7cb, 0x01df00, 0x01df09, 0x01df0b, 0x01df1e, 0x01e922, 0x01e943)); } private static void populateGC_LM() { SET_ENCODINGS.put("gc=Lm", CodePointSet.createNoDedup(0x0002b0, 0x0002c1, 0x0002c6, 0x0002d1, 0x0002e0, 0x0002e4, 0x0002ec, 0x0002ec, 0x0002ee, 0x0002ee, 0x000374, 0x000374, 0x00037a, 0x00037a, 0x000559, - 0x000559, 0x000640, 0x000640, 0x0006e5, 0x0006e6, 0x0007f4, 0x0007f5, 0x0007fa, 0x0007fa, 0x00081a, 0x00081a, 0x000824, 0x000824, 0x000828, 0x000828, 0x000971, - 0x000971, 0x000e46, 0x000e46, 0x000ec6, 0x000ec6, 0x0010fc, 0x0010fc, 0x0017d7, 0x0017d7, 0x001843, 0x001843, 0x001aa7, 0x001aa7, 0x001c78, 0x001c7d, 0x001d2c, - 0x001d6a, 0x001d78, 0x001d78, 0x001d9b, 0x001dbf, 0x002071, 0x002071, 0x00207f, 0x00207f, 0x002090, 0x00209c, 0x002c7c, 0x002c7d, 0x002d6f, 0x002d6f, 0x002e2f, - 0x002e2f, 0x003005, 0x003005, 0x003031, 0x003035, 0x00303b, 0x00303b, 0x00309d, 0x00309e, 0x0030fc, 0x0030fe, 0x00a015, 0x00a015, 0x00a4f8, 0x00a4fd, 0x00a60c, - 0x00a60c, 0x00a67f, 0x00a67f, 0x00a69c, 0x00a69d, 0x00a717, 0x00a71f, 0x00a770, 0x00a770, 0x00a788, 0x00a788, 0x00a7f8, 0x00a7f9, 0x00a9cf, 0x00a9cf, 0x00a9e6, - 0x00a9e6, 0x00aa70, 0x00aa70, 0x00aadd, 0x00aadd, 0x00aaf3, 0x00aaf4, 0x00ab5c, 0x00ab5f, 0x00ab69, 0x00ab69, 0x00ff70, 0x00ff70, 0x00ff9e, 0x00ff9f, 0x016b40, - 0x016b43, 0x016f93, 0x016f9f, 0x016fe0, 0x016fe1, 0x016fe3, 0x016fe3, 0x01e137, 0x01e13d, 0x01e94b, 0x01e94b)); + 0x000559, 0x000640, 0x000640, 0x0006e5, 0x0006e6, 0x0007f4, 0x0007f5, 0x0007fa, 0x0007fa, 0x00081a, 0x00081a, 0x000824, 0x000824, 0x000828, 0x000828, 0x0008c9, + 0x0008c9, 0x000971, 0x000971, 0x000e46, 0x000e46, 0x000ec6, 0x000ec6, 0x0010fc, 0x0010fc, 0x0017d7, 0x0017d7, 0x001843, 0x001843, 0x001aa7, 0x001aa7, 0x001c78, + 0x001c7d, 0x001d2c, 0x001d6a, 0x001d78, 0x001d78, 0x001d9b, 0x001dbf, 0x002071, 0x002071, 0x00207f, 0x00207f, 0x002090, 0x00209c, 0x002c7c, 0x002c7d, 0x002d6f, + 0x002d6f, 0x002e2f, 0x002e2f, 0x003005, 0x003005, 0x003031, 0x003035, 0x00303b, 0x00303b, 0x00309d, 0x00309e, 0x0030fc, 0x0030fe, 0x00a015, 0x00a015, 0x00a4f8, + 0x00a4fd, 0x00a60c, 0x00a60c, 0x00a67f, 0x00a67f, 0x00a69c, 0x00a69d, 0x00a717, 0x00a71f, 0x00a770, 0x00a770, 0x00a788, 0x00a788, 0x00a7f2, 0x00a7f4, 0x00a7f8, + 0x00a7f9, 0x00a9cf, 0x00a9cf, 0x00a9e6, 0x00a9e6, 0x00aa70, 0x00aa70, 0x00aadd, 0x00aadd, 0x00aaf3, 0x00aaf4, 0x00ab5c, 0x00ab5f, 0x00ab69, 0x00ab69, 0x00ff70, + 0x00ff70, 0x00ff9e, 0x00ff9f, 0x010780, 0x010785, 0x010787, 0x0107b0, 0x0107b2, 0x0107ba, 0x016b40, 0x016b43, 0x016f93, 0x016f9f, 0x016fe0, 0x016fe1, 0x016fe3, + 0x016fe3, 0x01aff0, 0x01aff3, 0x01aff5, 0x01affb, 0x01affd, 0x01affe, 0x01e137, 0x01e13d, 0x01e94b, 0x01e94b)); } private static void populateGC_LO() { SET_ENCODINGS.put("gc=Lo", CodePointSet.createNoDedup(0x0000aa, 0x0000aa, 0x0000ba, 0x0000ba, 0x0001bb, 0x0001bb, 0x0001c0, 0x0001c3, 0x000294, 0x000294, 0x0005d0, 0x0005ea, 0x0005ef, 0x0005f2, 0x000620, 0x00063f, 0x000641, 0x00064a, 0x00066e, 0x00066f, 0x000671, 0x0006d3, 0x0006d5, 0x0006d5, 0x0006ee, 0x0006ef, 0x0006fa, 0x0006fc, 0x0006ff, 0x0006ff, - 0x000710, 0x000710, 0x000712, 0x00072f, 0x00074d, 0x0007a5, 0x0007b1, 0x0007b1, 0x0007ca, 0x0007ea, 0x000800, 0x000815, 0x000840, 0x000858, 0x000860, 0x00086a, 0x0008a0, - 0x0008b4, 0x0008b6, 0x0008c7, 0x000904, 0x000939, 0x00093d, 0x00093d, 0x000950, 0x000950, 0x000958, 0x000961, 0x000972, 0x000980, 0x000985, 0x00098c, 0x00098f, 0x000990, - 0x000993, 0x0009a8, 0x0009aa, 0x0009b0, 0x0009b2, 0x0009b2, 0x0009b6, 0x0009b9, 0x0009bd, 0x0009bd, 0x0009ce, 0x0009ce, 0x0009dc, 0x0009dd, 0x0009df, 0x0009e1, 0x0009f0, - 0x0009f1, 0x0009fc, 0x0009fc, 0x000a05, 0x000a0a, 0x000a0f, 0x000a10, 0x000a13, 0x000a28, 0x000a2a, 0x000a30, 0x000a32, 0x000a33, 0x000a35, 0x000a36, 0x000a38, 0x000a39, - 0x000a59, 0x000a5c, 0x000a5e, 0x000a5e, 0x000a72, 0x000a74, 0x000a85, 0x000a8d, 0x000a8f, 0x000a91, 0x000a93, 0x000aa8, 0x000aaa, 0x000ab0, 0x000ab2, 0x000ab3, 0x000ab5, - 0x000ab9, 0x000abd, 0x000abd, 0x000ad0, 0x000ad0, 0x000ae0, 0x000ae1, 0x000af9, 0x000af9, 0x000b05, 0x000b0c, 0x000b0f, 0x000b10, 0x000b13, 0x000b28, 0x000b2a, 0x000b30, - 0x000b32, 0x000b33, 0x000b35, 0x000b39, 0x000b3d, 0x000b3d, 0x000b5c, 0x000b5d, 0x000b5f, 0x000b61, 0x000b71, 0x000b71, 0x000b83, 0x000b83, 0x000b85, 0x000b8a, 0x000b8e, - 0x000b90, 0x000b92, 0x000b95, 0x000b99, 0x000b9a, 0x000b9c, 0x000b9c, 0x000b9e, 0x000b9f, 0x000ba3, 0x000ba4, 0x000ba8, 0x000baa, 0x000bae, 0x000bb9, 0x000bd0, 0x000bd0, - 0x000c05, 0x000c0c, 0x000c0e, 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3d, 0x000c3d, 0x000c58, 0x000c5a, 0x000c60, 0x000c61, 0x000c80, 0x000c80, 0x000c85, - 0x000c8c, 0x000c8e, 0x000c90, 0x000c92, 0x000ca8, 0x000caa, 0x000cb3, 0x000cb5, 0x000cb9, 0x000cbd, 0x000cbd, 0x000cde, 0x000cde, 0x000ce0, 0x000ce1, 0x000cf1, 0x000cf2, - 0x000d04, 0x000d0c, 0x000d0e, 0x000d10, 0x000d12, 0x000d3a, 0x000d3d, 0x000d3d, 0x000d4e, 0x000d4e, 0x000d54, 0x000d56, 0x000d5f, 0x000d61, 0x000d7a, 0x000d7f, 0x000d85, - 0x000d96, 0x000d9a, 0x000db1, 0x000db3, 0x000dbb, 0x000dbd, 0x000dbd, 0x000dc0, 0x000dc6, 0x000e01, 0x000e30, 0x000e32, 0x000e33, 0x000e40, 0x000e45, 0x000e81, 0x000e82, - 0x000e84, 0x000e84, 0x000e86, 0x000e8a, 0x000e8c, 0x000ea3, 0x000ea5, 0x000ea5, 0x000ea7, 0x000eb0, 0x000eb2, 0x000eb3, 0x000ebd, 0x000ebd, 0x000ec0, 0x000ec4, 0x000edc, - 0x000edf, 0x000f00, 0x000f00, 0x000f40, 0x000f47, 0x000f49, 0x000f6c, 0x000f88, 0x000f8c, 0x001000, 0x00102a, 0x00103f, 0x00103f, 0x001050, 0x001055, 0x00105a, 0x00105d, - 0x001061, 0x001061, 0x001065, 0x001066, 0x00106e, 0x001070, 0x001075, 0x001081, 0x00108e, 0x00108e, 0x001100, 0x001248, 0x00124a, 0x00124d, 0x001250, 0x001256, 0x001258, - 0x001258, 0x00125a, 0x00125d, 0x001260, 0x001288, 0x00128a, 0x00128d, 0x001290, 0x0012b0, 0x0012b2, 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, - 0x0012c8, 0x0012d6, 0x0012d8, 0x001310, 0x001312, 0x001315, 0x001318, 0x00135a, 0x001380, 0x00138f, 0x001401, 0x00166c, 0x00166f, 0x00167f, 0x001681, 0x00169a, 0x0016a0, - 0x0016ea, 0x0016f1, 0x0016f8, 0x001700, 0x00170c, 0x00170e, 0x001711, 0x001720, 0x001731, 0x001740, 0x001751, 0x001760, 0x00176c, 0x00176e, 0x001770, 0x001780, 0x0017b3, - 0x0017dc, 0x0017dc, 0x001820, 0x001842, 0x001844, 0x001878, 0x001880, 0x001884, 0x001887, 0x0018a8, 0x0018aa, 0x0018aa, 0x0018b0, 0x0018f5, 0x001900, 0x00191e, 0x001950, - 0x00196d, 0x001970, 0x001974, 0x001980, 0x0019ab, 0x0019b0, 0x0019c9, 0x001a00, 0x001a16, 0x001a20, 0x001a54, 0x001b05, 0x001b33, 0x001b45, 0x001b4b, 0x001b83, 0x001ba0, - 0x001bae, 0x001baf, 0x001bba, 0x001be5, 0x001c00, 0x001c23, 0x001c4d, 0x001c4f, 0x001c5a, 0x001c77, 0x001ce9, 0x001cec, 0x001cee, 0x001cf3, 0x001cf5, 0x001cf6, 0x001cfa, - 0x001cfa, 0x002135, 0x002138, 0x002d30, 0x002d67, 0x002d80, 0x002d96, 0x002da0, 0x002da6, 0x002da8, 0x002dae, 0x002db0, 0x002db6, 0x002db8, 0x002dbe, 0x002dc0, 0x002dc6, - 0x002dc8, 0x002dce, 0x002dd0, 0x002dd6, 0x002dd8, 0x002dde, 0x003006, 0x003006, 0x00303c, 0x00303c, 0x003041, 0x003096, 0x00309f, 0x00309f, 0x0030a1, 0x0030fa, 0x0030ff, - 0x0030ff, 0x003105, 0x00312f, 0x003131, 0x00318e, 0x0031a0, 0x0031bf, 0x0031f0, 0x0031ff, 0x003400, 0x004dbf, 0x004e00, 0x009ffc, 0x00a000, 0x00a014, 0x00a016, 0x00a48c, + 0x000710, 0x000710, 0x000712, 0x00072f, 0x00074d, 0x0007a5, 0x0007b1, 0x0007b1, 0x0007ca, 0x0007ea, 0x000800, 0x000815, 0x000840, 0x000858, 0x000860, 0x00086a, 0x000870, + 0x000887, 0x000889, 0x00088e, 0x0008a0, 0x0008c8, 0x000904, 0x000939, 0x00093d, 0x00093d, 0x000950, 0x000950, 0x000958, 0x000961, 0x000972, 0x000980, 0x000985, 0x00098c, + 0x00098f, 0x000990, 0x000993, 0x0009a8, 0x0009aa, 0x0009b0, 0x0009b2, 0x0009b2, 0x0009b6, 0x0009b9, 0x0009bd, 0x0009bd, 0x0009ce, 0x0009ce, 0x0009dc, 0x0009dd, 0x0009df, + 0x0009e1, 0x0009f0, 0x0009f1, 0x0009fc, 0x0009fc, 0x000a05, 0x000a0a, 0x000a0f, 0x000a10, 0x000a13, 0x000a28, 0x000a2a, 0x000a30, 0x000a32, 0x000a33, 0x000a35, 0x000a36, + 0x000a38, 0x000a39, 0x000a59, 0x000a5c, 0x000a5e, 0x000a5e, 0x000a72, 0x000a74, 0x000a85, 0x000a8d, 0x000a8f, 0x000a91, 0x000a93, 0x000aa8, 0x000aaa, 0x000ab0, 0x000ab2, + 0x000ab3, 0x000ab5, 0x000ab9, 0x000abd, 0x000abd, 0x000ad0, 0x000ad0, 0x000ae0, 0x000ae1, 0x000af9, 0x000af9, 0x000b05, 0x000b0c, 0x000b0f, 0x000b10, 0x000b13, 0x000b28, + 0x000b2a, 0x000b30, 0x000b32, 0x000b33, 0x000b35, 0x000b39, 0x000b3d, 0x000b3d, 0x000b5c, 0x000b5d, 0x000b5f, 0x000b61, 0x000b71, 0x000b71, 0x000b83, 0x000b83, 0x000b85, + 0x000b8a, 0x000b8e, 0x000b90, 0x000b92, 0x000b95, 0x000b99, 0x000b9a, 0x000b9c, 0x000b9c, 0x000b9e, 0x000b9f, 0x000ba3, 0x000ba4, 0x000ba8, 0x000baa, 0x000bae, 0x000bb9, + 0x000bd0, 0x000bd0, 0x000c05, 0x000c0c, 0x000c0e, 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3d, 0x000c3d, 0x000c58, 0x000c5a, 0x000c5d, 0x000c5d, 0x000c60, + 0x000c61, 0x000c80, 0x000c80, 0x000c85, 0x000c8c, 0x000c8e, 0x000c90, 0x000c92, 0x000ca8, 0x000caa, 0x000cb3, 0x000cb5, 0x000cb9, 0x000cbd, 0x000cbd, 0x000cdd, 0x000cde, + 0x000ce0, 0x000ce1, 0x000cf1, 0x000cf2, 0x000d04, 0x000d0c, 0x000d0e, 0x000d10, 0x000d12, 0x000d3a, 0x000d3d, 0x000d3d, 0x000d4e, 0x000d4e, 0x000d54, 0x000d56, 0x000d5f, + 0x000d61, 0x000d7a, 0x000d7f, 0x000d85, 0x000d96, 0x000d9a, 0x000db1, 0x000db3, 0x000dbb, 0x000dbd, 0x000dbd, 0x000dc0, 0x000dc6, 0x000e01, 0x000e30, 0x000e32, 0x000e33, + 0x000e40, 0x000e45, 0x000e81, 0x000e82, 0x000e84, 0x000e84, 0x000e86, 0x000e8a, 0x000e8c, 0x000ea3, 0x000ea5, 0x000ea5, 0x000ea7, 0x000eb0, 0x000eb2, 0x000eb3, 0x000ebd, + 0x000ebd, 0x000ec0, 0x000ec4, 0x000edc, 0x000edf, 0x000f00, 0x000f00, 0x000f40, 0x000f47, 0x000f49, 0x000f6c, 0x000f88, 0x000f8c, 0x001000, 0x00102a, 0x00103f, 0x00103f, + 0x001050, 0x001055, 0x00105a, 0x00105d, 0x001061, 0x001061, 0x001065, 0x001066, 0x00106e, 0x001070, 0x001075, 0x001081, 0x00108e, 0x00108e, 0x001100, 0x001248, 0x00124a, + 0x00124d, 0x001250, 0x001256, 0x001258, 0x001258, 0x00125a, 0x00125d, 0x001260, 0x001288, 0x00128a, 0x00128d, 0x001290, 0x0012b0, 0x0012b2, 0x0012b5, 0x0012b8, 0x0012be, + 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, 0x0012d8, 0x001310, 0x001312, 0x001315, 0x001318, 0x00135a, 0x001380, 0x00138f, 0x001401, 0x00166c, 0x00166f, + 0x00167f, 0x001681, 0x00169a, 0x0016a0, 0x0016ea, 0x0016f1, 0x0016f8, 0x001700, 0x001711, 0x00171f, 0x001731, 0x001740, 0x001751, 0x001760, 0x00176c, 0x00176e, 0x001770, + 0x001780, 0x0017b3, 0x0017dc, 0x0017dc, 0x001820, 0x001842, 0x001844, 0x001878, 0x001880, 0x001884, 0x001887, 0x0018a8, 0x0018aa, 0x0018aa, 0x0018b0, 0x0018f5, 0x001900, + 0x00191e, 0x001950, 0x00196d, 0x001970, 0x001974, 0x001980, 0x0019ab, 0x0019b0, 0x0019c9, 0x001a00, 0x001a16, 0x001a20, 0x001a54, 0x001b05, 0x001b33, 0x001b45, 0x001b4c, + 0x001b83, 0x001ba0, 0x001bae, 0x001baf, 0x001bba, 0x001be5, 0x001c00, 0x001c23, 0x001c4d, 0x001c4f, 0x001c5a, 0x001c77, 0x001ce9, 0x001cec, 0x001cee, 0x001cf3, 0x001cf5, + 0x001cf6, 0x001cfa, 0x001cfa, 0x002135, 0x002138, 0x002d30, 0x002d67, 0x002d80, 0x002d96, 0x002da0, 0x002da6, 0x002da8, 0x002dae, 0x002db0, 0x002db6, 0x002db8, 0x002dbe, + 0x002dc0, 0x002dc6, 0x002dc8, 0x002dce, 0x002dd0, 0x002dd6, 0x002dd8, 0x002dde, 0x003006, 0x003006, 0x00303c, 0x00303c, 0x003041, 0x003096, 0x00309f, 0x00309f, 0x0030a1, + 0x0030fa, 0x0030ff, 0x0030ff, 0x003105, 0x00312f, 0x003131, 0x00318e, 0x0031a0, 0x0031bf, 0x0031f0, 0x0031ff, 0x003400, 0x004dbf, 0x004e00, 0x00a014, 0x00a016, 0x00a48c, 0x00a4d0, 0x00a4f7, 0x00a500, 0x00a60b, 0x00a610, 0x00a61f, 0x00a62a, 0x00a62b, 0x00a66e, 0x00a66e, 0x00a6a0, 0x00a6e5, 0x00a78f, 0x00a78f, 0x00a7f7, 0x00a7f7, 0x00a7fb, 0x00a801, 0x00a803, 0x00a805, 0x00a807, 0x00a80a, 0x00a80c, 0x00a822, 0x00a840, 0x00a873, 0x00a882, 0x00a8b3, 0x00a8f2, 0x00a8f7, 0x00a8fb, 0x00a8fb, 0x00a8fd, 0x00a8fe, 0x00a90a, 0x00a925, 0x00a930, 0x00a946, 0x00a960, 0x00a97c, 0x00a984, 0x00a9b2, 0x00a9e0, 0x00a9e4, 0x00a9e7, 0x00a9ef, 0x00a9fa, 0x00a9fe, 0x00aa00, 0x00aa28, 0x00aa40, @@ -2782,24 +2841,26 @@ private static void populateGC_LO() { 0x010805, 0x010808, 0x010808, 0x01080a, 0x010835, 0x010837, 0x010838, 0x01083c, 0x01083c, 0x01083f, 0x010855, 0x010860, 0x010876, 0x010880, 0x01089e, 0x0108e0, 0x0108f2, 0x0108f4, 0x0108f5, 0x010900, 0x010915, 0x010920, 0x010939, 0x010980, 0x0109b7, 0x0109be, 0x0109bf, 0x010a00, 0x010a00, 0x010a10, 0x010a13, 0x010a15, 0x010a17, 0x010a19, 0x010a35, 0x010a60, 0x010a7c, 0x010a80, 0x010a9c, 0x010ac0, 0x010ac7, 0x010ac9, 0x010ae4, 0x010b00, 0x010b35, 0x010b40, 0x010b55, 0x010b60, 0x010b72, 0x010b80, 0x010b91, - 0x010c00, 0x010c48, 0x010d00, 0x010d23, 0x010e80, 0x010ea9, 0x010eb0, 0x010eb1, 0x010f00, 0x010f1c, 0x010f27, 0x010f27, 0x010f30, 0x010f45, 0x010fb0, 0x010fc4, 0x010fe0, - 0x010ff6, 0x011003, 0x011037, 0x011083, 0x0110af, 0x0110d0, 0x0110e8, 0x011103, 0x011126, 0x011144, 0x011144, 0x011147, 0x011147, 0x011150, 0x011172, 0x011176, 0x011176, - 0x011183, 0x0111b2, 0x0111c1, 0x0111c4, 0x0111da, 0x0111da, 0x0111dc, 0x0111dc, 0x011200, 0x011211, 0x011213, 0x01122b, 0x011280, 0x011286, 0x011288, 0x011288, 0x01128a, - 0x01128d, 0x01128f, 0x01129d, 0x01129f, 0x0112a8, 0x0112b0, 0x0112de, 0x011305, 0x01130c, 0x01130f, 0x011310, 0x011313, 0x011328, 0x01132a, 0x011330, 0x011332, 0x011333, - 0x011335, 0x011339, 0x01133d, 0x01133d, 0x011350, 0x011350, 0x01135d, 0x011361, 0x011400, 0x011434, 0x011447, 0x01144a, 0x01145f, 0x011461, 0x011480, 0x0114af, 0x0114c4, - 0x0114c5, 0x0114c7, 0x0114c7, 0x011580, 0x0115ae, 0x0115d8, 0x0115db, 0x011600, 0x01162f, 0x011644, 0x011644, 0x011680, 0x0116aa, 0x0116b8, 0x0116b8, 0x011700, 0x01171a, - 0x011800, 0x01182b, 0x0118ff, 0x011906, 0x011909, 0x011909, 0x01190c, 0x011913, 0x011915, 0x011916, 0x011918, 0x01192f, 0x01193f, 0x01193f, 0x011941, 0x011941, 0x0119a0, - 0x0119a7, 0x0119aa, 0x0119d0, 0x0119e1, 0x0119e1, 0x0119e3, 0x0119e3, 0x011a00, 0x011a00, 0x011a0b, 0x011a32, 0x011a3a, 0x011a3a, 0x011a50, 0x011a50, 0x011a5c, 0x011a89, - 0x011a9d, 0x011a9d, 0x011ac0, 0x011af8, 0x011c00, 0x011c08, 0x011c0a, 0x011c2e, 0x011c40, 0x011c40, 0x011c72, 0x011c8f, 0x011d00, 0x011d06, 0x011d08, 0x011d09, 0x011d0b, - 0x011d30, 0x011d46, 0x011d46, 0x011d60, 0x011d65, 0x011d67, 0x011d68, 0x011d6a, 0x011d89, 0x011d98, 0x011d98, 0x011ee0, 0x011ef2, 0x011fb0, 0x011fb0, 0x012000, 0x012399, - 0x012480, 0x012543, 0x013000, 0x01342e, 0x014400, 0x014646, 0x016800, 0x016a38, 0x016a40, 0x016a5e, 0x016ad0, 0x016aed, 0x016b00, 0x016b2f, 0x016b63, 0x016b77, 0x016b7d, - 0x016b8f, 0x016f00, 0x016f4a, 0x016f50, 0x016f50, 0x017000, 0x0187f7, 0x018800, 0x018cd5, 0x018d00, 0x018d08, 0x01b000, 0x01b11e, 0x01b150, 0x01b152, 0x01b164, 0x01b167, - 0x01b170, 0x01b2fb, 0x01bc00, 0x01bc6a, 0x01bc70, 0x01bc7c, 0x01bc80, 0x01bc88, 0x01bc90, 0x01bc99, 0x01e100, 0x01e12c, 0x01e14e, 0x01e14e, 0x01e2c0, 0x01e2eb, 0x01e800, - 0x01e8c4, 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, 0x01ee39, - 0x01ee3b, 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, 0x01ee57, - 0x01ee57, 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, 0x01ee72, - 0x01ee74, 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, 0x01ee80, 0x01ee89, 0x01ee8b, 0x01ee9b, 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, 0x020000, - 0x02a6dd, 0x02a700, 0x02b734, 0x02b740, 0x02b81d, 0x02b820, 0x02cea1, 0x02ceb0, 0x02ebe0, 0x02f800, 0x02fa1d, 0x030000, 0x03134a)); + 0x010c00, 0x010c48, 0x010d00, 0x010d23, 0x010e80, 0x010ea9, 0x010eb0, 0x010eb1, 0x010f00, 0x010f1c, 0x010f27, 0x010f27, 0x010f30, 0x010f45, 0x010f70, 0x010f81, 0x010fb0, + 0x010fc4, 0x010fe0, 0x010ff6, 0x011003, 0x011037, 0x011071, 0x011072, 0x011075, 0x011075, 0x011083, 0x0110af, 0x0110d0, 0x0110e8, 0x011103, 0x011126, 0x011144, 0x011144, + 0x011147, 0x011147, 0x011150, 0x011172, 0x011176, 0x011176, 0x011183, 0x0111b2, 0x0111c1, 0x0111c4, 0x0111da, 0x0111da, 0x0111dc, 0x0111dc, 0x011200, 0x011211, 0x011213, + 0x01122b, 0x011280, 0x011286, 0x011288, 0x011288, 0x01128a, 0x01128d, 0x01128f, 0x01129d, 0x01129f, 0x0112a8, 0x0112b0, 0x0112de, 0x011305, 0x01130c, 0x01130f, 0x011310, + 0x011313, 0x011328, 0x01132a, 0x011330, 0x011332, 0x011333, 0x011335, 0x011339, 0x01133d, 0x01133d, 0x011350, 0x011350, 0x01135d, 0x011361, 0x011400, 0x011434, 0x011447, + 0x01144a, 0x01145f, 0x011461, 0x011480, 0x0114af, 0x0114c4, 0x0114c5, 0x0114c7, 0x0114c7, 0x011580, 0x0115ae, 0x0115d8, 0x0115db, 0x011600, 0x01162f, 0x011644, 0x011644, + 0x011680, 0x0116aa, 0x0116b8, 0x0116b8, 0x011700, 0x01171a, 0x011740, 0x011746, 0x011800, 0x01182b, 0x0118ff, 0x011906, 0x011909, 0x011909, 0x01190c, 0x011913, 0x011915, + 0x011916, 0x011918, 0x01192f, 0x01193f, 0x01193f, 0x011941, 0x011941, 0x0119a0, 0x0119a7, 0x0119aa, 0x0119d0, 0x0119e1, 0x0119e1, 0x0119e3, 0x0119e3, 0x011a00, 0x011a00, + 0x011a0b, 0x011a32, 0x011a3a, 0x011a3a, 0x011a50, 0x011a50, 0x011a5c, 0x011a89, 0x011a9d, 0x011a9d, 0x011ab0, 0x011af8, 0x011c00, 0x011c08, 0x011c0a, 0x011c2e, 0x011c40, + 0x011c40, 0x011c72, 0x011c8f, 0x011d00, 0x011d06, 0x011d08, 0x011d09, 0x011d0b, 0x011d30, 0x011d46, 0x011d46, 0x011d60, 0x011d65, 0x011d67, 0x011d68, 0x011d6a, 0x011d89, + 0x011d98, 0x011d98, 0x011ee0, 0x011ef2, 0x011fb0, 0x011fb0, 0x012000, 0x012399, 0x012480, 0x012543, 0x012f90, 0x012ff0, 0x013000, 0x01342e, 0x014400, 0x014646, 0x016800, + 0x016a38, 0x016a40, 0x016a5e, 0x016a70, 0x016abe, 0x016ad0, 0x016aed, 0x016b00, 0x016b2f, 0x016b63, 0x016b77, 0x016b7d, 0x016b8f, 0x016f00, 0x016f4a, 0x016f50, 0x016f50, + 0x017000, 0x0187f7, 0x018800, 0x018cd5, 0x018d00, 0x018d08, 0x01b000, 0x01b122, 0x01b150, 0x01b152, 0x01b164, 0x01b167, 0x01b170, 0x01b2fb, 0x01bc00, 0x01bc6a, 0x01bc70, + 0x01bc7c, 0x01bc80, 0x01bc88, 0x01bc90, 0x01bc99, 0x01df0a, 0x01df0a, 0x01e100, 0x01e12c, 0x01e14e, 0x01e14e, 0x01e290, 0x01e2ad, 0x01e2c0, 0x01e2eb, 0x01e7e0, 0x01e7e6, + 0x01e7e8, 0x01e7eb, 0x01e7ed, 0x01e7ee, 0x01e7f0, 0x01e7fe, 0x01e800, 0x01e8c4, 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, + 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, 0x01ee39, 0x01ee3b, 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, + 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, 0x01ee57, 0x01ee57, 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, + 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, 0x01ee72, 0x01ee74, 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, 0x01ee80, 0x01ee89, 0x01ee8b, 0x01ee9b, + 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, 0x020000, 0x02a6df, 0x02a700, 0x02b738, 0x02b740, 0x02b81d, 0x02b820, 0x02cea1, 0x02ceb0, 0x02ebe0, 0x02f800, + 0x02fa1d, 0x030000, 0x03134a)); } private static void populateGC_LT() { @@ -2859,7 +2920,7 @@ private static void populateGC_LU() { 0x001f48, 0x001f4d, 0x001f59, 0x001f59, 0x001f5b, 0x001f5b, 0x001f5d, 0x001f5d, 0x001f5f, 0x001f5f, 0x001f68, 0x001f6f, 0x001fb8, 0x001fbb, 0x001fc8, 0x001fcb, 0x001fd8, 0x001fdb, 0x001fe8, 0x001fec, 0x001ff8, 0x001ffb, 0x002102, 0x002102, 0x002107, 0x002107, 0x00210b, 0x00210d, 0x002110, 0x002112, 0x002115, 0x002115, 0x002119, 0x00211d, 0x002124, 0x002124, 0x002126, 0x002126, 0x002128, 0x002128, 0x00212a, 0x00212d, 0x002130, 0x002133, 0x00213e, 0x00213f, 0x002145, 0x002145, 0x002183, 0x002183, 0x002c00, - 0x002c2e, 0x002c60, 0x002c60, 0x002c62, 0x002c64, 0x002c67, 0x002c67, 0x002c69, 0x002c69, 0x002c6b, 0x002c6b, 0x002c6d, 0x002c70, 0x002c72, 0x002c72, 0x002c75, 0x002c75, + 0x002c2f, 0x002c60, 0x002c60, 0x002c62, 0x002c64, 0x002c67, 0x002c67, 0x002c69, 0x002c69, 0x002c6b, 0x002c6b, 0x002c6d, 0x002c70, 0x002c72, 0x002c72, 0x002c75, 0x002c75, 0x002c7e, 0x002c80, 0x002c82, 0x002c82, 0x002c84, 0x002c84, 0x002c86, 0x002c86, 0x002c88, 0x002c88, 0x002c8a, 0x002c8a, 0x002c8c, 0x002c8c, 0x002c8e, 0x002c8e, 0x002c90, 0x002c90, 0x002c92, 0x002c92, 0x002c94, 0x002c94, 0x002c96, 0x002c96, 0x002c98, 0x002c98, 0x002c9a, 0x002c9a, 0x002c9c, 0x002c9c, 0x002c9e, 0x002c9e, 0x002ca0, 0x002ca0, 0x002ca2, 0x002ca2, 0x002ca4, 0x002ca4, 0x002ca6, 0x002ca6, 0x002ca8, 0x002ca8, 0x002caa, 0x002caa, 0x002cac, 0x002cac, 0x002cae, 0x002cae, 0x002cb0, 0x002cb0, 0x002cb2, @@ -2878,12 +2939,13 @@ private static void populateGC_LU() { 0x00a76e, 0x00a779, 0x00a779, 0x00a77b, 0x00a77b, 0x00a77d, 0x00a77e, 0x00a780, 0x00a780, 0x00a782, 0x00a782, 0x00a784, 0x00a784, 0x00a786, 0x00a786, 0x00a78b, 0x00a78b, 0x00a78d, 0x00a78d, 0x00a790, 0x00a790, 0x00a792, 0x00a792, 0x00a796, 0x00a796, 0x00a798, 0x00a798, 0x00a79a, 0x00a79a, 0x00a79c, 0x00a79c, 0x00a79e, 0x00a79e, 0x00a7a0, 0x00a7a0, 0x00a7a2, 0x00a7a2, 0x00a7a4, 0x00a7a4, 0x00a7a6, 0x00a7a6, 0x00a7a8, 0x00a7a8, 0x00a7aa, 0x00a7ae, 0x00a7b0, 0x00a7b4, 0x00a7b6, 0x00a7b6, 0x00a7b8, 0x00a7b8, - 0x00a7ba, 0x00a7ba, 0x00a7bc, 0x00a7bc, 0x00a7be, 0x00a7be, 0x00a7c2, 0x00a7c2, 0x00a7c4, 0x00a7c7, 0x00a7c9, 0x00a7c9, 0x00a7f5, 0x00a7f5, 0x00ff21, 0x00ff3a, 0x010400, - 0x010427, 0x0104b0, 0x0104d3, 0x010c80, 0x010cb2, 0x0118a0, 0x0118bf, 0x016e40, 0x016e5f, 0x01d400, 0x01d419, 0x01d434, 0x01d44d, 0x01d468, 0x01d481, 0x01d49c, 0x01d49c, - 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b5, 0x01d4d0, 0x01d4e9, 0x01d504, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, - 0x01d514, 0x01d516, 0x01d51c, 0x01d538, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d56c, 0x01d585, 0x01d5a0, 0x01d5b9, - 0x01d5d4, 0x01d5ed, 0x01d608, 0x01d621, 0x01d63c, 0x01d655, 0x01d670, 0x01d689, 0x01d6a8, 0x01d6c0, 0x01d6e2, 0x01d6fa, 0x01d71c, 0x01d734, 0x01d756, 0x01d76e, 0x01d790, - 0x01d7a8, 0x01d7ca, 0x01d7ca, 0x01e900, 0x01e921)); + 0x00a7ba, 0x00a7ba, 0x00a7bc, 0x00a7bc, 0x00a7be, 0x00a7be, 0x00a7c0, 0x00a7c0, 0x00a7c2, 0x00a7c2, 0x00a7c4, 0x00a7c7, 0x00a7c9, 0x00a7c9, 0x00a7d0, 0x00a7d0, 0x00a7d6, + 0x00a7d6, 0x00a7d8, 0x00a7d8, 0x00a7f5, 0x00a7f5, 0x00ff21, 0x00ff3a, 0x010400, 0x010427, 0x0104b0, 0x0104d3, 0x010570, 0x01057a, 0x01057c, 0x01058a, 0x01058c, 0x010592, + 0x010594, 0x010595, 0x010c80, 0x010cb2, 0x0118a0, 0x0118bf, 0x016e40, 0x016e5f, 0x01d400, 0x01d419, 0x01d434, 0x01d44d, 0x01d468, 0x01d481, 0x01d49c, 0x01d49c, 0x01d49e, + 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b5, 0x01d4d0, 0x01d4e9, 0x01d504, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, + 0x01d516, 0x01d51c, 0x01d538, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d56c, 0x01d585, 0x01d5a0, 0x01d5b9, 0x01d5d4, + 0x01d5ed, 0x01d608, 0x01d621, 0x01d63c, 0x01d655, 0x01d670, 0x01d689, 0x01d6a8, 0x01d6c0, 0x01d6e2, 0x01d6fa, 0x01d71c, 0x01d734, 0x01d756, 0x01d76e, 0x01d790, 0x01d7a8, + 0x01d7ca, 0x01d7ca, 0x01e900, 0x01e921)); } private static void populateGC_MC() { @@ -2893,21 +2955,22 @@ private static void populateGC_MC() { 0x000bc2, 0x000bc6, 0x000bc8, 0x000bca, 0x000bcc, 0x000bd7, 0x000bd7, 0x000c01, 0x000c03, 0x000c41, 0x000c44, 0x000c82, 0x000c83, 0x000cbe, 0x000cbe, 0x000cc0, 0x000cc4, 0x000cc7, 0x000cc8, 0x000cca, 0x000ccb, 0x000cd5, 0x000cd6, 0x000d02, 0x000d03, 0x000d3e, 0x000d40, 0x000d46, 0x000d48, 0x000d4a, 0x000d4c, 0x000d57, 0x000d57, 0x000d82, 0x000d83, 0x000dcf, 0x000dd1, 0x000dd8, 0x000ddf, 0x000df2, 0x000df3, 0x000f3e, 0x000f3f, 0x000f7f, 0x000f7f, 0x00102b, 0x00102c, 0x001031, 0x001031, 0x001038, 0x001038, - 0x00103b, 0x00103c, 0x001056, 0x001057, 0x001062, 0x001064, 0x001067, 0x00106d, 0x001083, 0x001084, 0x001087, 0x00108c, 0x00108f, 0x00108f, 0x00109a, 0x00109c, 0x0017b6, - 0x0017b6, 0x0017be, 0x0017c5, 0x0017c7, 0x0017c8, 0x001923, 0x001926, 0x001929, 0x00192b, 0x001930, 0x001931, 0x001933, 0x001938, 0x001a19, 0x001a1a, 0x001a55, 0x001a55, - 0x001a57, 0x001a57, 0x001a61, 0x001a61, 0x001a63, 0x001a64, 0x001a6d, 0x001a72, 0x001b04, 0x001b04, 0x001b35, 0x001b35, 0x001b3b, 0x001b3b, 0x001b3d, 0x001b41, 0x001b43, - 0x001b44, 0x001b82, 0x001b82, 0x001ba1, 0x001ba1, 0x001ba6, 0x001ba7, 0x001baa, 0x001baa, 0x001be7, 0x001be7, 0x001bea, 0x001bec, 0x001bee, 0x001bee, 0x001bf2, 0x001bf3, - 0x001c24, 0x001c2b, 0x001c34, 0x001c35, 0x001ce1, 0x001ce1, 0x001cf7, 0x001cf7, 0x00302e, 0x00302f, 0x00a823, 0x00a824, 0x00a827, 0x00a827, 0x00a880, 0x00a881, 0x00a8b4, - 0x00a8c3, 0x00a952, 0x00a953, 0x00a983, 0x00a983, 0x00a9b4, 0x00a9b5, 0x00a9ba, 0x00a9bb, 0x00a9be, 0x00a9c0, 0x00aa2f, 0x00aa30, 0x00aa33, 0x00aa34, 0x00aa4d, 0x00aa4d, - 0x00aa7b, 0x00aa7b, 0x00aa7d, 0x00aa7d, 0x00aaeb, 0x00aaeb, 0x00aaee, 0x00aaef, 0x00aaf5, 0x00aaf5, 0x00abe3, 0x00abe4, 0x00abe6, 0x00abe7, 0x00abe9, 0x00abea, 0x00abec, - 0x00abec, 0x011000, 0x011000, 0x011002, 0x011002, 0x011082, 0x011082, 0x0110b0, 0x0110b2, 0x0110b7, 0x0110b8, 0x01112c, 0x01112c, 0x011145, 0x011146, 0x011182, 0x011182, - 0x0111b3, 0x0111b5, 0x0111bf, 0x0111c0, 0x0111ce, 0x0111ce, 0x01122c, 0x01122e, 0x011232, 0x011233, 0x011235, 0x011235, 0x0112e0, 0x0112e2, 0x011302, 0x011303, 0x01133e, - 0x01133f, 0x011341, 0x011344, 0x011347, 0x011348, 0x01134b, 0x01134d, 0x011357, 0x011357, 0x011362, 0x011363, 0x011435, 0x011437, 0x011440, 0x011441, 0x011445, 0x011445, - 0x0114b0, 0x0114b2, 0x0114b9, 0x0114b9, 0x0114bb, 0x0114be, 0x0114c1, 0x0114c1, 0x0115af, 0x0115b1, 0x0115b8, 0x0115bb, 0x0115be, 0x0115be, 0x011630, 0x011632, 0x01163b, - 0x01163c, 0x01163e, 0x01163e, 0x0116ac, 0x0116ac, 0x0116ae, 0x0116af, 0x0116b6, 0x0116b6, 0x011720, 0x011721, 0x011726, 0x011726, 0x01182c, 0x01182e, 0x011838, 0x011838, - 0x011930, 0x011935, 0x011937, 0x011938, 0x01193d, 0x01193d, 0x011940, 0x011940, 0x011942, 0x011942, 0x0119d1, 0x0119d3, 0x0119dc, 0x0119df, 0x0119e4, 0x0119e4, 0x011a39, - 0x011a39, 0x011a57, 0x011a58, 0x011a97, 0x011a97, 0x011c2f, 0x011c2f, 0x011c3e, 0x011c3e, 0x011ca9, 0x011ca9, 0x011cb1, 0x011cb1, 0x011cb4, 0x011cb4, 0x011d8a, 0x011d8e, - 0x011d93, 0x011d94, 0x011d96, 0x011d96, 0x011ef5, 0x011ef6, 0x016f51, 0x016f87, 0x016ff0, 0x016ff1, 0x01d165, 0x01d166, 0x01d16d, 0x01d172)); + 0x00103b, 0x00103c, 0x001056, 0x001057, 0x001062, 0x001064, 0x001067, 0x00106d, 0x001083, 0x001084, 0x001087, 0x00108c, 0x00108f, 0x00108f, 0x00109a, 0x00109c, 0x001715, + 0x001715, 0x001734, 0x001734, 0x0017b6, 0x0017b6, 0x0017be, 0x0017c5, 0x0017c7, 0x0017c8, 0x001923, 0x001926, 0x001929, 0x00192b, 0x001930, 0x001931, 0x001933, 0x001938, + 0x001a19, 0x001a1a, 0x001a55, 0x001a55, 0x001a57, 0x001a57, 0x001a61, 0x001a61, 0x001a63, 0x001a64, 0x001a6d, 0x001a72, 0x001b04, 0x001b04, 0x001b35, 0x001b35, 0x001b3b, + 0x001b3b, 0x001b3d, 0x001b41, 0x001b43, 0x001b44, 0x001b82, 0x001b82, 0x001ba1, 0x001ba1, 0x001ba6, 0x001ba7, 0x001baa, 0x001baa, 0x001be7, 0x001be7, 0x001bea, 0x001bec, + 0x001bee, 0x001bee, 0x001bf2, 0x001bf3, 0x001c24, 0x001c2b, 0x001c34, 0x001c35, 0x001ce1, 0x001ce1, 0x001cf7, 0x001cf7, 0x00302e, 0x00302f, 0x00a823, 0x00a824, 0x00a827, + 0x00a827, 0x00a880, 0x00a881, 0x00a8b4, 0x00a8c3, 0x00a952, 0x00a953, 0x00a983, 0x00a983, 0x00a9b4, 0x00a9b5, 0x00a9ba, 0x00a9bb, 0x00a9be, 0x00a9c0, 0x00aa2f, 0x00aa30, + 0x00aa33, 0x00aa34, 0x00aa4d, 0x00aa4d, 0x00aa7b, 0x00aa7b, 0x00aa7d, 0x00aa7d, 0x00aaeb, 0x00aaeb, 0x00aaee, 0x00aaef, 0x00aaf5, 0x00aaf5, 0x00abe3, 0x00abe4, 0x00abe6, + 0x00abe7, 0x00abe9, 0x00abea, 0x00abec, 0x00abec, 0x011000, 0x011000, 0x011002, 0x011002, 0x011082, 0x011082, 0x0110b0, 0x0110b2, 0x0110b7, 0x0110b8, 0x01112c, 0x01112c, + 0x011145, 0x011146, 0x011182, 0x011182, 0x0111b3, 0x0111b5, 0x0111bf, 0x0111c0, 0x0111ce, 0x0111ce, 0x01122c, 0x01122e, 0x011232, 0x011233, 0x011235, 0x011235, 0x0112e0, + 0x0112e2, 0x011302, 0x011303, 0x01133e, 0x01133f, 0x011341, 0x011344, 0x011347, 0x011348, 0x01134b, 0x01134d, 0x011357, 0x011357, 0x011362, 0x011363, 0x011435, 0x011437, + 0x011440, 0x011441, 0x011445, 0x011445, 0x0114b0, 0x0114b2, 0x0114b9, 0x0114b9, 0x0114bb, 0x0114be, 0x0114c1, 0x0114c1, 0x0115af, 0x0115b1, 0x0115b8, 0x0115bb, 0x0115be, + 0x0115be, 0x011630, 0x011632, 0x01163b, 0x01163c, 0x01163e, 0x01163e, 0x0116ac, 0x0116ac, 0x0116ae, 0x0116af, 0x0116b6, 0x0116b6, 0x011720, 0x011721, 0x011726, 0x011726, + 0x01182c, 0x01182e, 0x011838, 0x011838, 0x011930, 0x011935, 0x011937, 0x011938, 0x01193d, 0x01193d, 0x011940, 0x011940, 0x011942, 0x011942, 0x0119d1, 0x0119d3, 0x0119dc, + 0x0119df, 0x0119e4, 0x0119e4, 0x011a39, 0x011a39, 0x011a57, 0x011a58, 0x011a97, 0x011a97, 0x011c2f, 0x011c2f, 0x011c3e, 0x011c3e, 0x011ca9, 0x011ca9, 0x011cb1, 0x011cb1, + 0x011cb4, 0x011cb4, 0x011d8a, 0x011d8e, 0x011d93, 0x011d94, 0x011d96, 0x011d96, 0x011ef5, 0x011ef6, 0x016f51, 0x016f87, 0x016ff0, 0x016ff1, 0x01d165, 0x01d166, 0x01d16d, + 0x01d172)); } private static void populateGC_ME() { @@ -2918,42 +2981,43 @@ private static void populateGC_MN() { SET_ENCODINGS.put("gc=Mn", CodePointSet.createNoDedup(0x000300, 0x00036f, 0x000483, 0x000487, 0x000591, 0x0005bd, 0x0005bf, 0x0005bf, 0x0005c1, 0x0005c2, 0x0005c4, 0x0005c5, 0x0005c7, 0x0005c7, 0x000610, 0x00061a, 0x00064b, 0x00065f, 0x000670, 0x000670, 0x0006d6, 0x0006dc, 0x0006df, 0x0006e4, 0x0006e7, 0x0006e8, 0x0006ea, 0x0006ed, 0x000711, 0x000711, 0x000730, 0x00074a, 0x0007a6, 0x0007b0, 0x0007eb, 0x0007f3, 0x0007fd, 0x0007fd, 0x000816, 0x000819, 0x00081b, 0x000823, 0x000825, 0x000827, 0x000829, 0x00082d, 0x000859, - 0x00085b, 0x0008d3, 0x0008e1, 0x0008e3, 0x000902, 0x00093a, 0x00093a, 0x00093c, 0x00093c, 0x000941, 0x000948, 0x00094d, 0x00094d, 0x000951, 0x000957, 0x000962, 0x000963, - 0x000981, 0x000981, 0x0009bc, 0x0009bc, 0x0009c1, 0x0009c4, 0x0009cd, 0x0009cd, 0x0009e2, 0x0009e3, 0x0009fe, 0x0009fe, 0x000a01, 0x000a02, 0x000a3c, 0x000a3c, 0x000a41, - 0x000a42, 0x000a47, 0x000a48, 0x000a4b, 0x000a4d, 0x000a51, 0x000a51, 0x000a70, 0x000a71, 0x000a75, 0x000a75, 0x000a81, 0x000a82, 0x000abc, 0x000abc, 0x000ac1, 0x000ac5, - 0x000ac7, 0x000ac8, 0x000acd, 0x000acd, 0x000ae2, 0x000ae3, 0x000afa, 0x000aff, 0x000b01, 0x000b01, 0x000b3c, 0x000b3c, 0x000b3f, 0x000b3f, 0x000b41, 0x000b44, 0x000b4d, - 0x000b4d, 0x000b55, 0x000b56, 0x000b62, 0x000b63, 0x000b82, 0x000b82, 0x000bc0, 0x000bc0, 0x000bcd, 0x000bcd, 0x000c00, 0x000c00, 0x000c04, 0x000c04, 0x000c3e, 0x000c40, - 0x000c46, 0x000c48, 0x000c4a, 0x000c4d, 0x000c55, 0x000c56, 0x000c62, 0x000c63, 0x000c81, 0x000c81, 0x000cbc, 0x000cbc, 0x000cbf, 0x000cbf, 0x000cc6, 0x000cc6, 0x000ccc, - 0x000ccd, 0x000ce2, 0x000ce3, 0x000d00, 0x000d01, 0x000d3b, 0x000d3c, 0x000d41, 0x000d44, 0x000d4d, 0x000d4d, 0x000d62, 0x000d63, 0x000d81, 0x000d81, 0x000dca, 0x000dca, - 0x000dd2, 0x000dd4, 0x000dd6, 0x000dd6, 0x000e31, 0x000e31, 0x000e34, 0x000e3a, 0x000e47, 0x000e4e, 0x000eb1, 0x000eb1, 0x000eb4, 0x000ebc, 0x000ec8, 0x000ecd, 0x000f18, - 0x000f19, 0x000f35, 0x000f35, 0x000f37, 0x000f37, 0x000f39, 0x000f39, 0x000f71, 0x000f7e, 0x000f80, 0x000f84, 0x000f86, 0x000f87, 0x000f8d, 0x000f97, 0x000f99, 0x000fbc, - 0x000fc6, 0x000fc6, 0x00102d, 0x001030, 0x001032, 0x001037, 0x001039, 0x00103a, 0x00103d, 0x00103e, 0x001058, 0x001059, 0x00105e, 0x001060, 0x001071, 0x001074, 0x001082, - 0x001082, 0x001085, 0x001086, 0x00108d, 0x00108d, 0x00109d, 0x00109d, 0x00135d, 0x00135f, 0x001712, 0x001714, 0x001732, 0x001734, 0x001752, 0x001753, 0x001772, 0x001773, - 0x0017b4, 0x0017b5, 0x0017b7, 0x0017bd, 0x0017c6, 0x0017c6, 0x0017c9, 0x0017d3, 0x0017dd, 0x0017dd, 0x00180b, 0x00180d, 0x001885, 0x001886, 0x0018a9, 0x0018a9, 0x001920, - 0x001922, 0x001927, 0x001928, 0x001932, 0x001932, 0x001939, 0x00193b, 0x001a17, 0x001a18, 0x001a1b, 0x001a1b, 0x001a56, 0x001a56, 0x001a58, 0x001a5e, 0x001a60, 0x001a60, - 0x001a62, 0x001a62, 0x001a65, 0x001a6c, 0x001a73, 0x001a7c, 0x001a7f, 0x001a7f, 0x001ab0, 0x001abd, 0x001abf, 0x001ac0, 0x001b00, 0x001b03, 0x001b34, 0x001b34, 0x001b36, - 0x001b3a, 0x001b3c, 0x001b3c, 0x001b42, 0x001b42, 0x001b6b, 0x001b73, 0x001b80, 0x001b81, 0x001ba2, 0x001ba5, 0x001ba8, 0x001ba9, 0x001bab, 0x001bad, 0x001be6, 0x001be6, - 0x001be8, 0x001be9, 0x001bed, 0x001bed, 0x001bef, 0x001bf1, 0x001c2c, 0x001c33, 0x001c36, 0x001c37, 0x001cd0, 0x001cd2, 0x001cd4, 0x001ce0, 0x001ce2, 0x001ce8, 0x001ced, - 0x001ced, 0x001cf4, 0x001cf4, 0x001cf8, 0x001cf9, 0x001dc0, 0x001df9, 0x001dfb, 0x001dff, 0x0020d0, 0x0020dc, 0x0020e1, 0x0020e1, 0x0020e5, 0x0020f0, 0x002cef, 0x002cf1, - 0x002d7f, 0x002d7f, 0x002de0, 0x002dff, 0x00302a, 0x00302d, 0x003099, 0x00309a, 0x00a66f, 0x00a66f, 0x00a674, 0x00a67d, 0x00a69e, 0x00a69f, 0x00a6f0, 0x00a6f1, 0x00a802, - 0x00a802, 0x00a806, 0x00a806, 0x00a80b, 0x00a80b, 0x00a825, 0x00a826, 0x00a82c, 0x00a82c, 0x00a8c4, 0x00a8c5, 0x00a8e0, 0x00a8f1, 0x00a8ff, 0x00a8ff, 0x00a926, 0x00a92d, - 0x00a947, 0x00a951, 0x00a980, 0x00a982, 0x00a9b3, 0x00a9b3, 0x00a9b6, 0x00a9b9, 0x00a9bc, 0x00a9bd, 0x00a9e5, 0x00a9e5, 0x00aa29, 0x00aa2e, 0x00aa31, 0x00aa32, 0x00aa35, - 0x00aa36, 0x00aa43, 0x00aa43, 0x00aa4c, 0x00aa4c, 0x00aa7c, 0x00aa7c, 0x00aab0, 0x00aab0, 0x00aab2, 0x00aab4, 0x00aab7, 0x00aab8, 0x00aabe, 0x00aabf, 0x00aac1, 0x00aac1, - 0x00aaec, 0x00aaed, 0x00aaf6, 0x00aaf6, 0x00abe5, 0x00abe5, 0x00abe8, 0x00abe8, 0x00abed, 0x00abed, 0x00fb1e, 0x00fb1e, 0x00fe00, 0x00fe0f, 0x00fe20, 0x00fe2f, 0x0101fd, - 0x0101fd, 0x0102e0, 0x0102e0, 0x010376, 0x01037a, 0x010a01, 0x010a03, 0x010a05, 0x010a06, 0x010a0c, 0x010a0f, 0x010a38, 0x010a3a, 0x010a3f, 0x010a3f, 0x010ae5, 0x010ae6, - 0x010d24, 0x010d27, 0x010eab, 0x010eac, 0x010f46, 0x010f50, 0x011001, 0x011001, 0x011038, 0x011046, 0x01107f, 0x011081, 0x0110b3, 0x0110b6, 0x0110b9, 0x0110ba, 0x011100, - 0x011102, 0x011127, 0x01112b, 0x01112d, 0x011134, 0x011173, 0x011173, 0x011180, 0x011181, 0x0111b6, 0x0111be, 0x0111c9, 0x0111cc, 0x0111cf, 0x0111cf, 0x01122f, 0x011231, - 0x011234, 0x011234, 0x011236, 0x011237, 0x01123e, 0x01123e, 0x0112df, 0x0112df, 0x0112e3, 0x0112ea, 0x011300, 0x011301, 0x01133b, 0x01133c, 0x011340, 0x011340, 0x011366, - 0x01136c, 0x011370, 0x011374, 0x011438, 0x01143f, 0x011442, 0x011444, 0x011446, 0x011446, 0x01145e, 0x01145e, 0x0114b3, 0x0114b8, 0x0114ba, 0x0114ba, 0x0114bf, 0x0114c0, - 0x0114c2, 0x0114c3, 0x0115b2, 0x0115b5, 0x0115bc, 0x0115bd, 0x0115bf, 0x0115c0, 0x0115dc, 0x0115dd, 0x011633, 0x01163a, 0x01163d, 0x01163d, 0x01163f, 0x011640, 0x0116ab, - 0x0116ab, 0x0116ad, 0x0116ad, 0x0116b0, 0x0116b5, 0x0116b7, 0x0116b7, 0x01171d, 0x01171f, 0x011722, 0x011725, 0x011727, 0x01172b, 0x01182f, 0x011837, 0x011839, 0x01183a, - 0x01193b, 0x01193c, 0x01193e, 0x01193e, 0x011943, 0x011943, 0x0119d4, 0x0119d7, 0x0119da, 0x0119db, 0x0119e0, 0x0119e0, 0x011a01, 0x011a0a, 0x011a33, 0x011a38, 0x011a3b, - 0x011a3e, 0x011a47, 0x011a47, 0x011a51, 0x011a56, 0x011a59, 0x011a5b, 0x011a8a, 0x011a96, 0x011a98, 0x011a99, 0x011c30, 0x011c36, 0x011c38, 0x011c3d, 0x011c3f, 0x011c3f, - 0x011c92, 0x011ca7, 0x011caa, 0x011cb0, 0x011cb2, 0x011cb3, 0x011cb5, 0x011cb6, 0x011d31, 0x011d36, 0x011d3a, 0x011d3a, 0x011d3c, 0x011d3d, 0x011d3f, 0x011d45, 0x011d47, - 0x011d47, 0x011d90, 0x011d91, 0x011d95, 0x011d95, 0x011d97, 0x011d97, 0x011ef3, 0x011ef4, 0x016af0, 0x016af4, 0x016b30, 0x016b36, 0x016f4f, 0x016f4f, 0x016f8f, 0x016f92, - 0x016fe4, 0x016fe4, 0x01bc9d, 0x01bc9e, 0x01d167, 0x01d169, 0x01d17b, 0x01d182, 0x01d185, 0x01d18b, 0x01d1aa, 0x01d1ad, 0x01d242, 0x01d244, 0x01da00, 0x01da36, 0x01da3b, - 0x01da6c, 0x01da75, 0x01da75, 0x01da84, 0x01da84, 0x01da9b, 0x01da9f, 0x01daa1, 0x01daaf, 0x01e000, 0x01e006, 0x01e008, 0x01e018, 0x01e01b, 0x01e021, 0x01e023, 0x01e024, - 0x01e026, 0x01e02a, 0x01e130, 0x01e136, 0x01e2ec, 0x01e2ef, 0x01e8d0, 0x01e8d6, 0x01e944, 0x01e94a, 0x0e0100, 0x0e01ef)); + 0x00085b, 0x000898, 0x00089f, 0x0008ca, 0x0008e1, 0x0008e3, 0x000902, 0x00093a, 0x00093a, 0x00093c, 0x00093c, 0x000941, 0x000948, 0x00094d, 0x00094d, 0x000951, 0x000957, + 0x000962, 0x000963, 0x000981, 0x000981, 0x0009bc, 0x0009bc, 0x0009c1, 0x0009c4, 0x0009cd, 0x0009cd, 0x0009e2, 0x0009e3, 0x0009fe, 0x0009fe, 0x000a01, 0x000a02, 0x000a3c, + 0x000a3c, 0x000a41, 0x000a42, 0x000a47, 0x000a48, 0x000a4b, 0x000a4d, 0x000a51, 0x000a51, 0x000a70, 0x000a71, 0x000a75, 0x000a75, 0x000a81, 0x000a82, 0x000abc, 0x000abc, + 0x000ac1, 0x000ac5, 0x000ac7, 0x000ac8, 0x000acd, 0x000acd, 0x000ae2, 0x000ae3, 0x000afa, 0x000aff, 0x000b01, 0x000b01, 0x000b3c, 0x000b3c, 0x000b3f, 0x000b3f, 0x000b41, + 0x000b44, 0x000b4d, 0x000b4d, 0x000b55, 0x000b56, 0x000b62, 0x000b63, 0x000b82, 0x000b82, 0x000bc0, 0x000bc0, 0x000bcd, 0x000bcd, 0x000c00, 0x000c00, 0x000c04, 0x000c04, + 0x000c3c, 0x000c3c, 0x000c3e, 0x000c40, 0x000c46, 0x000c48, 0x000c4a, 0x000c4d, 0x000c55, 0x000c56, 0x000c62, 0x000c63, 0x000c81, 0x000c81, 0x000cbc, 0x000cbc, 0x000cbf, + 0x000cbf, 0x000cc6, 0x000cc6, 0x000ccc, 0x000ccd, 0x000ce2, 0x000ce3, 0x000d00, 0x000d01, 0x000d3b, 0x000d3c, 0x000d41, 0x000d44, 0x000d4d, 0x000d4d, 0x000d62, 0x000d63, + 0x000d81, 0x000d81, 0x000dca, 0x000dca, 0x000dd2, 0x000dd4, 0x000dd6, 0x000dd6, 0x000e31, 0x000e31, 0x000e34, 0x000e3a, 0x000e47, 0x000e4e, 0x000eb1, 0x000eb1, 0x000eb4, + 0x000ebc, 0x000ec8, 0x000ecd, 0x000f18, 0x000f19, 0x000f35, 0x000f35, 0x000f37, 0x000f37, 0x000f39, 0x000f39, 0x000f71, 0x000f7e, 0x000f80, 0x000f84, 0x000f86, 0x000f87, + 0x000f8d, 0x000f97, 0x000f99, 0x000fbc, 0x000fc6, 0x000fc6, 0x00102d, 0x001030, 0x001032, 0x001037, 0x001039, 0x00103a, 0x00103d, 0x00103e, 0x001058, 0x001059, 0x00105e, + 0x001060, 0x001071, 0x001074, 0x001082, 0x001082, 0x001085, 0x001086, 0x00108d, 0x00108d, 0x00109d, 0x00109d, 0x00135d, 0x00135f, 0x001712, 0x001714, 0x001732, 0x001733, + 0x001752, 0x001753, 0x001772, 0x001773, 0x0017b4, 0x0017b5, 0x0017b7, 0x0017bd, 0x0017c6, 0x0017c6, 0x0017c9, 0x0017d3, 0x0017dd, 0x0017dd, 0x00180b, 0x00180d, 0x00180f, + 0x00180f, 0x001885, 0x001886, 0x0018a9, 0x0018a9, 0x001920, 0x001922, 0x001927, 0x001928, 0x001932, 0x001932, 0x001939, 0x00193b, 0x001a17, 0x001a18, 0x001a1b, 0x001a1b, + 0x001a56, 0x001a56, 0x001a58, 0x001a5e, 0x001a60, 0x001a60, 0x001a62, 0x001a62, 0x001a65, 0x001a6c, 0x001a73, 0x001a7c, 0x001a7f, 0x001a7f, 0x001ab0, 0x001abd, 0x001abf, + 0x001ace, 0x001b00, 0x001b03, 0x001b34, 0x001b34, 0x001b36, 0x001b3a, 0x001b3c, 0x001b3c, 0x001b42, 0x001b42, 0x001b6b, 0x001b73, 0x001b80, 0x001b81, 0x001ba2, 0x001ba5, + 0x001ba8, 0x001ba9, 0x001bab, 0x001bad, 0x001be6, 0x001be6, 0x001be8, 0x001be9, 0x001bed, 0x001bed, 0x001bef, 0x001bf1, 0x001c2c, 0x001c33, 0x001c36, 0x001c37, 0x001cd0, + 0x001cd2, 0x001cd4, 0x001ce0, 0x001ce2, 0x001ce8, 0x001ced, 0x001ced, 0x001cf4, 0x001cf4, 0x001cf8, 0x001cf9, 0x001dc0, 0x001dff, 0x0020d0, 0x0020dc, 0x0020e1, 0x0020e1, + 0x0020e5, 0x0020f0, 0x002cef, 0x002cf1, 0x002d7f, 0x002d7f, 0x002de0, 0x002dff, 0x00302a, 0x00302d, 0x003099, 0x00309a, 0x00a66f, 0x00a66f, 0x00a674, 0x00a67d, 0x00a69e, + 0x00a69f, 0x00a6f0, 0x00a6f1, 0x00a802, 0x00a802, 0x00a806, 0x00a806, 0x00a80b, 0x00a80b, 0x00a825, 0x00a826, 0x00a82c, 0x00a82c, 0x00a8c4, 0x00a8c5, 0x00a8e0, 0x00a8f1, + 0x00a8ff, 0x00a8ff, 0x00a926, 0x00a92d, 0x00a947, 0x00a951, 0x00a980, 0x00a982, 0x00a9b3, 0x00a9b3, 0x00a9b6, 0x00a9b9, 0x00a9bc, 0x00a9bd, 0x00a9e5, 0x00a9e5, 0x00aa29, + 0x00aa2e, 0x00aa31, 0x00aa32, 0x00aa35, 0x00aa36, 0x00aa43, 0x00aa43, 0x00aa4c, 0x00aa4c, 0x00aa7c, 0x00aa7c, 0x00aab0, 0x00aab0, 0x00aab2, 0x00aab4, 0x00aab7, 0x00aab8, + 0x00aabe, 0x00aabf, 0x00aac1, 0x00aac1, 0x00aaec, 0x00aaed, 0x00aaf6, 0x00aaf6, 0x00abe5, 0x00abe5, 0x00abe8, 0x00abe8, 0x00abed, 0x00abed, 0x00fb1e, 0x00fb1e, 0x00fe00, + 0x00fe0f, 0x00fe20, 0x00fe2f, 0x0101fd, 0x0101fd, 0x0102e0, 0x0102e0, 0x010376, 0x01037a, 0x010a01, 0x010a03, 0x010a05, 0x010a06, 0x010a0c, 0x010a0f, 0x010a38, 0x010a3a, + 0x010a3f, 0x010a3f, 0x010ae5, 0x010ae6, 0x010d24, 0x010d27, 0x010eab, 0x010eac, 0x010f46, 0x010f50, 0x010f82, 0x010f85, 0x011001, 0x011001, 0x011038, 0x011046, 0x011070, + 0x011070, 0x011073, 0x011074, 0x01107f, 0x011081, 0x0110b3, 0x0110b6, 0x0110b9, 0x0110ba, 0x0110c2, 0x0110c2, 0x011100, 0x011102, 0x011127, 0x01112b, 0x01112d, 0x011134, + 0x011173, 0x011173, 0x011180, 0x011181, 0x0111b6, 0x0111be, 0x0111c9, 0x0111cc, 0x0111cf, 0x0111cf, 0x01122f, 0x011231, 0x011234, 0x011234, 0x011236, 0x011237, 0x01123e, + 0x01123e, 0x0112df, 0x0112df, 0x0112e3, 0x0112ea, 0x011300, 0x011301, 0x01133b, 0x01133c, 0x011340, 0x011340, 0x011366, 0x01136c, 0x011370, 0x011374, 0x011438, 0x01143f, + 0x011442, 0x011444, 0x011446, 0x011446, 0x01145e, 0x01145e, 0x0114b3, 0x0114b8, 0x0114ba, 0x0114ba, 0x0114bf, 0x0114c0, 0x0114c2, 0x0114c3, 0x0115b2, 0x0115b5, 0x0115bc, + 0x0115bd, 0x0115bf, 0x0115c0, 0x0115dc, 0x0115dd, 0x011633, 0x01163a, 0x01163d, 0x01163d, 0x01163f, 0x011640, 0x0116ab, 0x0116ab, 0x0116ad, 0x0116ad, 0x0116b0, 0x0116b5, + 0x0116b7, 0x0116b7, 0x01171d, 0x01171f, 0x011722, 0x011725, 0x011727, 0x01172b, 0x01182f, 0x011837, 0x011839, 0x01183a, 0x01193b, 0x01193c, 0x01193e, 0x01193e, 0x011943, + 0x011943, 0x0119d4, 0x0119d7, 0x0119da, 0x0119db, 0x0119e0, 0x0119e0, 0x011a01, 0x011a0a, 0x011a33, 0x011a38, 0x011a3b, 0x011a3e, 0x011a47, 0x011a47, 0x011a51, 0x011a56, + 0x011a59, 0x011a5b, 0x011a8a, 0x011a96, 0x011a98, 0x011a99, 0x011c30, 0x011c36, 0x011c38, 0x011c3d, 0x011c3f, 0x011c3f, 0x011c92, 0x011ca7, 0x011caa, 0x011cb0, 0x011cb2, + 0x011cb3, 0x011cb5, 0x011cb6, 0x011d31, 0x011d36, 0x011d3a, 0x011d3a, 0x011d3c, 0x011d3d, 0x011d3f, 0x011d45, 0x011d47, 0x011d47, 0x011d90, 0x011d91, 0x011d95, 0x011d95, + 0x011d97, 0x011d97, 0x011ef3, 0x011ef4, 0x016af0, 0x016af4, 0x016b30, 0x016b36, 0x016f4f, 0x016f4f, 0x016f8f, 0x016f92, 0x016fe4, 0x016fe4, 0x01bc9d, 0x01bc9e, 0x01cf00, + 0x01cf2d, 0x01cf30, 0x01cf46, 0x01d167, 0x01d169, 0x01d17b, 0x01d182, 0x01d185, 0x01d18b, 0x01d1aa, 0x01d1ad, 0x01d242, 0x01d244, 0x01da00, 0x01da36, 0x01da3b, 0x01da6c, + 0x01da75, 0x01da75, 0x01da84, 0x01da84, 0x01da9b, 0x01da9f, 0x01daa1, 0x01daaf, 0x01e000, 0x01e006, 0x01e008, 0x01e018, 0x01e01b, 0x01e021, 0x01e023, 0x01e024, 0x01e026, + 0x01e02a, 0x01e130, 0x01e136, 0x01e2ae, 0x01e2ae, 0x01e2ec, 0x01e2ef, 0x01e8d0, 0x01e8d6, 0x01e944, 0x01e94a, 0x0e0100, 0x0e01ef)); } private static void populateGC_ND() { @@ -2964,8 +3028,8 @@ private static void populateGC_ND() { 0x001a89, 0x001a90, 0x001a99, 0x001b50, 0x001b59, 0x001bb0, 0x001bb9, 0x001c40, 0x001c49, 0x001c50, 0x001c59, 0x00a620, 0x00a629, 0x00a8d0, 0x00a8d9, 0x00a900, 0x00a909, 0x00a9d0, 0x00a9d9, 0x00a9f0, 0x00a9f9, 0x00aa50, 0x00aa59, 0x00abf0, 0x00abf9, 0x00ff10, 0x00ff19, 0x0104a0, 0x0104a9, 0x010d30, 0x010d39, 0x011066, 0x01106f, 0x0110f0, 0x0110f9, 0x011136, 0x01113f, 0x0111d0, 0x0111d9, 0x0112f0, 0x0112f9, 0x011450, 0x011459, 0x0114d0, 0x0114d9, 0x011650, 0x011659, 0x0116c0, - 0x0116c9, 0x011730, 0x011739, 0x0118e0, 0x0118e9, 0x011950, 0x011959, 0x011c50, 0x011c59, 0x011d50, 0x011d59, 0x011da0, 0x011da9, 0x016a60, 0x016a69, 0x016b50, - 0x016b59, 0x01d7ce, 0x01d7ff, 0x01e140, 0x01e149, 0x01e2f0, 0x01e2f9, 0x01e950, 0x01e959, 0x01fbf0, 0x01fbf9)); + 0x0116c9, 0x011730, 0x011739, 0x0118e0, 0x0118e9, 0x011950, 0x011959, 0x011c50, 0x011c59, 0x011d50, 0x011d59, 0x011da0, 0x011da9, 0x016a60, 0x016a69, 0x016ac0, + 0x016ac9, 0x016b50, 0x016b59, 0x01d7ce, 0x01d7ff, 0x01e140, 0x01e149, 0x01e2f0, 0x01e2f9, 0x01e950, 0x01e959, 0x01fbf0, 0x01fbf9)); } private static void populateGC_NL() { @@ -2993,20 +3057,22 @@ private static void populateGC_PC() { private static void populateGC_PD() { SET_ENCODINGS.put("gc=Pd", CodePointSet.createNoDedup(0x00002d, 0x00002d, 0x00058a, 0x00058a, 0x0005be, 0x0005be, 0x001400, 0x001400, 0x001806, 0x001806, 0x002010, 0x002015, 0x002e17, 0x002e17, 0x002e1a, - 0x002e1a, 0x002e3a, 0x002e3b, 0x002e40, 0x002e40, 0x00301c, 0x00301c, 0x003030, 0x003030, 0x0030a0, 0x0030a0, 0x00fe31, 0x00fe32, 0x00fe58, 0x00fe58, 0x00fe63, - 0x00fe63, 0x00ff0d, 0x00ff0d, 0x010ead, 0x010ead)); + 0x002e1a, 0x002e3a, 0x002e3b, 0x002e40, 0x002e40, 0x002e5d, 0x002e5d, 0x00301c, 0x00301c, 0x003030, 0x003030, 0x0030a0, 0x0030a0, 0x00fe31, 0x00fe32, 0x00fe58, + 0x00fe58, 0x00fe63, 0x00fe63, 0x00ff0d, 0x00ff0d, 0x010ead, 0x010ead)); } private static void populateGC_PE() { - SET_ENCODINGS.put("gc=Pe", CodePointSet.createNoDedup(0x000029, 0x000029, 0x00005d, 0x00005d, 0x00007d, 0x00007d, 0x000f3b, 0x000f3b, 0x000f3d, 0x000f3d, 0x00169c, 0x00169c, 0x002046, - 0x002046, 0x00207e, 0x00207e, 0x00208e, 0x00208e, 0x002309, 0x002309, 0x00230b, 0x00230b, 0x00232a, 0x00232a, 0x002769, 0x002769, 0x00276b, 0x00276b, 0x00276d, 0x00276d, - 0x00276f, 0x00276f, 0x002771, 0x002771, 0x002773, 0x002773, 0x002775, 0x002775, 0x0027c6, 0x0027c6, 0x0027e7, 0x0027e7, 0x0027e9, 0x0027e9, 0x0027eb, 0x0027eb, 0x0027ed, - 0x0027ed, 0x0027ef, 0x0027ef, 0x002984, 0x002984, 0x002986, 0x002986, 0x002988, 0x002988, 0x00298a, 0x00298a, 0x00298c, 0x00298c, 0x00298e, 0x00298e, 0x002990, 0x002990, - 0x002992, 0x002992, 0x002994, 0x002994, 0x002996, 0x002996, 0x002998, 0x002998, 0x0029d9, 0x0029d9, 0x0029db, 0x0029db, 0x0029fd, 0x0029fd, 0x002e23, 0x002e23, 0x002e25, - 0x002e25, 0x002e27, 0x002e27, 0x002e29, 0x002e29, 0x003009, 0x003009, 0x00300b, 0x00300b, 0x00300d, 0x00300d, 0x00300f, 0x00300f, 0x003011, 0x003011, 0x003015, 0x003015, - 0x003017, 0x003017, 0x003019, 0x003019, 0x00301b, 0x00301b, 0x00301e, 0x00301f, 0x00fd3e, 0x00fd3e, 0x00fe18, 0x00fe18, 0x00fe36, 0x00fe36, 0x00fe38, 0x00fe38, 0x00fe3a, - 0x00fe3a, 0x00fe3c, 0x00fe3c, 0x00fe3e, 0x00fe3e, 0x00fe40, 0x00fe40, 0x00fe42, 0x00fe42, 0x00fe44, 0x00fe44, 0x00fe48, 0x00fe48, 0x00fe5a, 0x00fe5a, 0x00fe5c, 0x00fe5c, - 0x00fe5e, 0x00fe5e, 0x00ff09, 0x00ff09, 0x00ff3d, 0x00ff3d, 0x00ff5d, 0x00ff5d, 0x00ff60, 0x00ff60, 0x00ff63, 0x00ff63)); + SET_ENCODINGS.put("gc=Pe", + CodePointSet.createNoDedup(0x000029, 0x000029, 0x00005d, 0x00005d, 0x00007d, 0x00007d, 0x000f3b, 0x000f3b, 0x000f3d, 0x000f3d, 0x00169c, 0x00169c, 0x002046, 0x002046, 0x00207e, + 0x00207e, 0x00208e, 0x00208e, 0x002309, 0x002309, 0x00230b, 0x00230b, 0x00232a, 0x00232a, 0x002769, 0x002769, 0x00276b, 0x00276b, 0x00276d, 0x00276d, 0x00276f, + 0x00276f, 0x002771, 0x002771, 0x002773, 0x002773, 0x002775, 0x002775, 0x0027c6, 0x0027c6, 0x0027e7, 0x0027e7, 0x0027e9, 0x0027e9, 0x0027eb, 0x0027eb, 0x0027ed, + 0x0027ed, 0x0027ef, 0x0027ef, 0x002984, 0x002984, 0x002986, 0x002986, 0x002988, 0x002988, 0x00298a, 0x00298a, 0x00298c, 0x00298c, 0x00298e, 0x00298e, 0x002990, + 0x002990, 0x002992, 0x002992, 0x002994, 0x002994, 0x002996, 0x002996, 0x002998, 0x002998, 0x0029d9, 0x0029d9, 0x0029db, 0x0029db, 0x0029fd, 0x0029fd, 0x002e23, + 0x002e23, 0x002e25, 0x002e25, 0x002e27, 0x002e27, 0x002e29, 0x002e29, 0x002e56, 0x002e56, 0x002e58, 0x002e58, 0x002e5a, 0x002e5a, 0x002e5c, 0x002e5c, 0x003009, + 0x003009, 0x00300b, 0x00300b, 0x00300d, 0x00300d, 0x00300f, 0x00300f, 0x003011, 0x003011, 0x003015, 0x003015, 0x003017, 0x003017, 0x003019, 0x003019, 0x00301b, + 0x00301b, 0x00301e, 0x00301f, 0x00fd3e, 0x00fd3e, 0x00fe18, 0x00fe18, 0x00fe36, 0x00fe36, 0x00fe38, 0x00fe38, 0x00fe3a, 0x00fe3a, 0x00fe3c, 0x00fe3c, 0x00fe3e, + 0x00fe3e, 0x00fe40, 0x00fe40, 0x00fe42, 0x00fe42, 0x00fe44, 0x00fe44, 0x00fe48, 0x00fe48, 0x00fe5a, 0x00fe5a, 0x00fe5c, 0x00fe5c, 0x00fe5e, 0x00fe5e, 0x00ff09, + 0x00ff09, 0x00ff3d, 0x00ff3d, 0x00ff5d, 0x00ff5d, 0x00ff60, 0x00ff60, 0x00ff63, 0x00ff63)); } private static void populateGC_PF() { @@ -3022,26 +3088,26 @@ private static void populateGC_PI() { private static void populateGC_PO() { SET_ENCODINGS.put("gc=Po", CodePointSet.createNoDedup(0x000021, 0x000023, 0x000025, 0x000027, 0x00002a, 0x00002a, 0x00002c, 0x00002c, 0x00002e, 0x00002f, 0x00003a, 0x00003b, 0x00003f, 0x000040, 0x00005c, 0x00005c, 0x0000a1, 0x0000a1, 0x0000a7, 0x0000a7, 0x0000b6, 0x0000b7, 0x0000bf, 0x0000bf, 0x00037e, 0x00037e, 0x000387, 0x000387, 0x00055a, 0x00055f, - 0x000589, 0x000589, 0x0005c0, 0x0005c0, 0x0005c3, 0x0005c3, 0x0005c6, 0x0005c6, 0x0005f3, 0x0005f4, 0x000609, 0x00060a, 0x00060c, 0x00060d, 0x00061b, 0x00061b, 0x00061e, + 0x000589, 0x000589, 0x0005c0, 0x0005c0, 0x0005c3, 0x0005c3, 0x0005c6, 0x0005c6, 0x0005f3, 0x0005f4, 0x000609, 0x00060a, 0x00060c, 0x00060d, 0x00061b, 0x00061b, 0x00061d, 0x00061f, 0x00066a, 0x00066d, 0x0006d4, 0x0006d4, 0x000700, 0x00070d, 0x0007f7, 0x0007f9, 0x000830, 0x00083e, 0x00085e, 0x00085e, 0x000964, 0x000965, 0x000970, 0x000970, 0x0009fd, 0x0009fd, 0x000a76, 0x000a76, 0x000af0, 0x000af0, 0x000c77, 0x000c77, 0x000c84, 0x000c84, 0x000df4, 0x000df4, 0x000e4f, 0x000e4f, 0x000e5a, 0x000e5b, 0x000f04, 0x000f12, 0x000f14, 0x000f14, 0x000f85, 0x000f85, 0x000fd0, 0x000fd4, 0x000fd9, 0x000fda, 0x00104a, 0x00104f, 0x0010fb, 0x0010fb, 0x001360, 0x001368, 0x00166e, 0x00166e, 0x0016eb, 0x0016ed, 0x001735, 0x001736, 0x0017d4, 0x0017d6, 0x0017d8, 0x0017da, 0x001800, 0x001805, 0x001807, 0x00180a, 0x001944, 0x001945, 0x001a1e, 0x001a1f, 0x001aa0, - 0x001aa6, 0x001aa8, 0x001aad, 0x001b5a, 0x001b60, 0x001bfc, 0x001bff, 0x001c3b, 0x001c3f, 0x001c7e, 0x001c7f, 0x001cc0, 0x001cc7, 0x001cd3, 0x001cd3, 0x002016, 0x002017, - 0x002020, 0x002027, 0x002030, 0x002038, 0x00203b, 0x00203e, 0x002041, 0x002043, 0x002047, 0x002051, 0x002053, 0x002053, 0x002055, 0x00205e, 0x002cf9, 0x002cfc, 0x002cfe, - 0x002cff, 0x002d70, 0x002d70, 0x002e00, 0x002e01, 0x002e06, 0x002e08, 0x002e0b, 0x002e0b, 0x002e0e, 0x002e16, 0x002e18, 0x002e19, 0x002e1b, 0x002e1b, 0x002e1e, 0x002e1f, - 0x002e2a, 0x002e2e, 0x002e30, 0x002e39, 0x002e3c, 0x002e3f, 0x002e41, 0x002e41, 0x002e43, 0x002e4f, 0x002e52, 0x002e52, 0x003001, 0x003003, 0x00303d, 0x00303d, 0x0030fb, - 0x0030fb, 0x00a4fe, 0x00a4ff, 0x00a60d, 0x00a60f, 0x00a673, 0x00a673, 0x00a67e, 0x00a67e, 0x00a6f2, 0x00a6f7, 0x00a874, 0x00a877, 0x00a8ce, 0x00a8cf, 0x00a8f8, 0x00a8fa, - 0x00a8fc, 0x00a8fc, 0x00a92e, 0x00a92f, 0x00a95f, 0x00a95f, 0x00a9c1, 0x00a9cd, 0x00a9de, 0x00a9df, 0x00aa5c, 0x00aa5f, 0x00aade, 0x00aadf, 0x00aaf0, 0x00aaf1, 0x00abeb, - 0x00abeb, 0x00fe10, 0x00fe16, 0x00fe19, 0x00fe19, 0x00fe30, 0x00fe30, 0x00fe45, 0x00fe46, 0x00fe49, 0x00fe4c, 0x00fe50, 0x00fe52, 0x00fe54, 0x00fe57, 0x00fe5f, 0x00fe61, - 0x00fe68, 0x00fe68, 0x00fe6a, 0x00fe6b, 0x00ff01, 0x00ff03, 0x00ff05, 0x00ff07, 0x00ff0a, 0x00ff0a, 0x00ff0c, 0x00ff0c, 0x00ff0e, 0x00ff0f, 0x00ff1a, 0x00ff1b, 0x00ff1f, - 0x00ff20, 0x00ff3c, 0x00ff3c, 0x00ff61, 0x00ff61, 0x00ff64, 0x00ff65, 0x010100, 0x010102, 0x01039f, 0x01039f, 0x0103d0, 0x0103d0, 0x01056f, 0x01056f, 0x010857, 0x010857, - 0x01091f, 0x01091f, 0x01093f, 0x01093f, 0x010a50, 0x010a58, 0x010a7f, 0x010a7f, 0x010af0, 0x010af6, 0x010b39, 0x010b3f, 0x010b99, 0x010b9c, 0x010f55, 0x010f59, 0x011047, - 0x01104d, 0x0110bb, 0x0110bc, 0x0110be, 0x0110c1, 0x011140, 0x011143, 0x011174, 0x011175, 0x0111c5, 0x0111c8, 0x0111cd, 0x0111cd, 0x0111db, 0x0111db, 0x0111dd, 0x0111df, - 0x011238, 0x01123d, 0x0112a9, 0x0112a9, 0x01144b, 0x01144f, 0x01145a, 0x01145b, 0x01145d, 0x01145d, 0x0114c6, 0x0114c6, 0x0115c1, 0x0115d7, 0x011641, 0x011643, 0x011660, - 0x01166c, 0x01173c, 0x01173e, 0x01183b, 0x01183b, 0x011944, 0x011946, 0x0119e2, 0x0119e2, 0x011a3f, 0x011a46, 0x011a9a, 0x011a9c, 0x011a9e, 0x011aa2, 0x011c41, 0x011c45, - 0x011c70, 0x011c71, 0x011ef7, 0x011ef8, 0x011fff, 0x011fff, 0x012470, 0x012474, 0x016a6e, 0x016a6f, 0x016af5, 0x016af5, 0x016b37, 0x016b3b, 0x016b44, 0x016b44, 0x016e97, - 0x016e9a, 0x016fe2, 0x016fe2, 0x01bc9f, 0x01bc9f, 0x01da87, 0x01da8b, 0x01e95e, 0x01e95f)); + 0x001aa6, 0x001aa8, 0x001aad, 0x001b5a, 0x001b60, 0x001b7d, 0x001b7e, 0x001bfc, 0x001bff, 0x001c3b, 0x001c3f, 0x001c7e, 0x001c7f, 0x001cc0, 0x001cc7, 0x001cd3, 0x001cd3, + 0x002016, 0x002017, 0x002020, 0x002027, 0x002030, 0x002038, 0x00203b, 0x00203e, 0x002041, 0x002043, 0x002047, 0x002051, 0x002053, 0x002053, 0x002055, 0x00205e, 0x002cf9, + 0x002cfc, 0x002cfe, 0x002cff, 0x002d70, 0x002d70, 0x002e00, 0x002e01, 0x002e06, 0x002e08, 0x002e0b, 0x002e0b, 0x002e0e, 0x002e16, 0x002e18, 0x002e19, 0x002e1b, 0x002e1b, + 0x002e1e, 0x002e1f, 0x002e2a, 0x002e2e, 0x002e30, 0x002e39, 0x002e3c, 0x002e3f, 0x002e41, 0x002e41, 0x002e43, 0x002e4f, 0x002e52, 0x002e54, 0x003001, 0x003003, 0x00303d, + 0x00303d, 0x0030fb, 0x0030fb, 0x00a4fe, 0x00a4ff, 0x00a60d, 0x00a60f, 0x00a673, 0x00a673, 0x00a67e, 0x00a67e, 0x00a6f2, 0x00a6f7, 0x00a874, 0x00a877, 0x00a8ce, 0x00a8cf, + 0x00a8f8, 0x00a8fa, 0x00a8fc, 0x00a8fc, 0x00a92e, 0x00a92f, 0x00a95f, 0x00a95f, 0x00a9c1, 0x00a9cd, 0x00a9de, 0x00a9df, 0x00aa5c, 0x00aa5f, 0x00aade, 0x00aadf, 0x00aaf0, + 0x00aaf1, 0x00abeb, 0x00abeb, 0x00fe10, 0x00fe16, 0x00fe19, 0x00fe19, 0x00fe30, 0x00fe30, 0x00fe45, 0x00fe46, 0x00fe49, 0x00fe4c, 0x00fe50, 0x00fe52, 0x00fe54, 0x00fe57, + 0x00fe5f, 0x00fe61, 0x00fe68, 0x00fe68, 0x00fe6a, 0x00fe6b, 0x00ff01, 0x00ff03, 0x00ff05, 0x00ff07, 0x00ff0a, 0x00ff0a, 0x00ff0c, 0x00ff0c, 0x00ff0e, 0x00ff0f, 0x00ff1a, + 0x00ff1b, 0x00ff1f, 0x00ff20, 0x00ff3c, 0x00ff3c, 0x00ff61, 0x00ff61, 0x00ff64, 0x00ff65, 0x010100, 0x010102, 0x01039f, 0x01039f, 0x0103d0, 0x0103d0, 0x01056f, 0x01056f, + 0x010857, 0x010857, 0x01091f, 0x01091f, 0x01093f, 0x01093f, 0x010a50, 0x010a58, 0x010a7f, 0x010a7f, 0x010af0, 0x010af6, 0x010b39, 0x010b3f, 0x010b99, 0x010b9c, 0x010f55, + 0x010f59, 0x010f86, 0x010f89, 0x011047, 0x01104d, 0x0110bb, 0x0110bc, 0x0110be, 0x0110c1, 0x011140, 0x011143, 0x011174, 0x011175, 0x0111c5, 0x0111c8, 0x0111cd, 0x0111cd, + 0x0111db, 0x0111db, 0x0111dd, 0x0111df, 0x011238, 0x01123d, 0x0112a9, 0x0112a9, 0x01144b, 0x01144f, 0x01145a, 0x01145b, 0x01145d, 0x01145d, 0x0114c6, 0x0114c6, 0x0115c1, + 0x0115d7, 0x011641, 0x011643, 0x011660, 0x01166c, 0x0116b9, 0x0116b9, 0x01173c, 0x01173e, 0x01183b, 0x01183b, 0x011944, 0x011946, 0x0119e2, 0x0119e2, 0x011a3f, 0x011a46, + 0x011a9a, 0x011a9c, 0x011a9e, 0x011aa2, 0x011c41, 0x011c45, 0x011c70, 0x011c71, 0x011ef7, 0x011ef8, 0x011fff, 0x011fff, 0x012470, 0x012474, 0x012ff1, 0x012ff2, 0x016a6e, + 0x016a6f, 0x016af5, 0x016af5, 0x016b37, 0x016b3b, 0x016b44, 0x016b44, 0x016e97, 0x016e9a, 0x016fe2, 0x016fe2, 0x01bc9f, 0x01bc9f, 0x01da87, 0x01da8b, 0x01e95e, 0x01e95f)); } private static void populateGC_PS() { @@ -3051,26 +3117,26 @@ private static void populateGC_PS() { 0x00276a, 0x00276c, 0x00276c, 0x00276e, 0x00276e, 0x002770, 0x002770, 0x002772, 0x002772, 0x002774, 0x002774, 0x0027c5, 0x0027c5, 0x0027e6, 0x0027e6, 0x0027e8, 0x0027e8, 0x0027ea, 0x0027ea, 0x0027ec, 0x0027ec, 0x0027ee, 0x0027ee, 0x002983, 0x002983, 0x002985, 0x002985, 0x002987, 0x002987, 0x002989, 0x002989, 0x00298b, 0x00298b, 0x00298d, 0x00298d, 0x00298f, 0x00298f, 0x002991, 0x002991, 0x002993, 0x002993, 0x002995, 0x002995, 0x002997, 0x002997, 0x0029d8, 0x0029d8, 0x0029da, - 0x0029da, 0x0029fc, 0x0029fc, 0x002e22, 0x002e22, 0x002e24, 0x002e24, 0x002e26, 0x002e26, 0x002e28, 0x002e28, 0x002e42, 0x002e42, 0x003008, 0x003008, 0x00300a, - 0x00300a, 0x00300c, 0x00300c, 0x00300e, 0x00300e, 0x003010, 0x003010, 0x003014, 0x003014, 0x003016, 0x003016, 0x003018, 0x003018, 0x00301a, 0x00301a, 0x00301d, - 0x00301d, 0x00fd3f, 0x00fd3f, 0x00fe17, 0x00fe17, 0x00fe35, 0x00fe35, 0x00fe37, 0x00fe37, 0x00fe39, 0x00fe39, 0x00fe3b, 0x00fe3b, 0x00fe3d, 0x00fe3d, 0x00fe3f, - 0x00fe3f, 0x00fe41, 0x00fe41, 0x00fe43, 0x00fe43, 0x00fe47, 0x00fe47, 0x00fe59, 0x00fe59, 0x00fe5b, 0x00fe5b, 0x00fe5d, 0x00fe5d, 0x00ff08, 0x00ff08, 0x00ff3b, - 0x00ff3b, 0x00ff5b, 0x00ff5b, 0x00ff5f, 0x00ff5f, 0x00ff62, 0x00ff62)); + 0x0029da, 0x0029fc, 0x0029fc, 0x002e22, 0x002e22, 0x002e24, 0x002e24, 0x002e26, 0x002e26, 0x002e28, 0x002e28, 0x002e42, 0x002e42, 0x002e55, 0x002e55, 0x002e57, + 0x002e57, 0x002e59, 0x002e59, 0x002e5b, 0x002e5b, 0x003008, 0x003008, 0x00300a, 0x00300a, 0x00300c, 0x00300c, 0x00300e, 0x00300e, 0x003010, 0x003010, 0x003014, + 0x003014, 0x003016, 0x003016, 0x003018, 0x003018, 0x00301a, 0x00301a, 0x00301d, 0x00301d, 0x00fd3f, 0x00fd3f, 0x00fe17, 0x00fe17, 0x00fe35, 0x00fe35, 0x00fe37, + 0x00fe37, 0x00fe39, 0x00fe39, 0x00fe3b, 0x00fe3b, 0x00fe3d, 0x00fe3d, 0x00fe3f, 0x00fe3f, 0x00fe41, 0x00fe41, 0x00fe43, 0x00fe43, 0x00fe47, 0x00fe47, 0x00fe59, + 0x00fe59, 0x00fe5b, 0x00fe5b, 0x00fe5d, 0x00fe5d, 0x00ff08, 0x00ff08, 0x00ff3b, 0x00ff3b, 0x00ff5b, 0x00ff5b, 0x00ff5f, 0x00ff5f, 0x00ff62, 0x00ff62)); } private static void populateGC_SC() { SET_ENCODINGS.put("gc=Sc", CodePointSet.createNoDedup(0x000024, 0x000024, 0x0000a2, 0x0000a5, 0x00058f, 0x00058f, 0x00060b, 0x00060b, 0x0007fe, 0x0007ff, 0x0009f2, 0x0009f3, 0x0009fb, 0x0009fb, 0x000af1, - 0x000af1, 0x000bf9, 0x000bf9, 0x000e3f, 0x000e3f, 0x0017db, 0x0017db, 0x0020a0, 0x0020bf, 0x00a838, 0x00a838, 0x00fdfc, 0x00fdfc, 0x00fe69, 0x00fe69, 0x00ff04, + 0x000af1, 0x000bf9, 0x000bf9, 0x000e3f, 0x000e3f, 0x0017db, 0x0017db, 0x0020a0, 0x0020c0, 0x00a838, 0x00a838, 0x00fdfc, 0x00fdfc, 0x00fe69, 0x00fe69, 0x00ff04, 0x00ff04, 0x00ffe0, 0x00ffe1, 0x00ffe5, 0x00ffe6, 0x011fdd, 0x011fe0, 0x01e2ff, 0x01e2ff, 0x01ecb0, 0x01ecb0)); } private static void populateGC_SK() { SET_ENCODINGS.put("gc=Sk", CodePointSet.createNoDedup(0x00005e, 0x00005e, 0x000060, 0x000060, 0x0000a8, 0x0000a8, 0x0000af, 0x0000af, 0x0000b4, 0x0000b4, 0x0000b8, 0x0000b8, 0x0002c2, 0x0002c5, 0x0002d2, - 0x0002df, 0x0002e5, 0x0002eb, 0x0002ed, 0x0002ed, 0x0002ef, 0x0002ff, 0x000375, 0x000375, 0x000384, 0x000385, 0x001fbd, 0x001fbd, 0x001fbf, 0x001fc1, 0x001fcd, - 0x001fcf, 0x001fdd, 0x001fdf, 0x001fed, 0x001fef, 0x001ffd, 0x001ffe, 0x00309b, 0x00309c, 0x00a700, 0x00a716, 0x00a720, 0x00a721, 0x00a789, 0x00a78a, 0x00ab5b, - 0x00ab5b, 0x00ab6a, 0x00ab6b, 0x00fbb2, 0x00fbc1, 0x00ff3e, 0x00ff3e, 0x00ff40, 0x00ff40, 0x00ffe3, 0x00ffe3, 0x01f3fb, 0x01f3ff)); + 0x0002df, 0x0002e5, 0x0002eb, 0x0002ed, 0x0002ed, 0x0002ef, 0x0002ff, 0x000375, 0x000375, 0x000384, 0x000385, 0x000888, 0x000888, 0x001fbd, 0x001fbd, 0x001fbf, + 0x001fc1, 0x001fcd, 0x001fcf, 0x001fdd, 0x001fdf, 0x001fed, 0x001fef, 0x001ffd, 0x001ffe, 0x00309b, 0x00309c, 0x00a700, 0x00a716, 0x00a720, 0x00a721, 0x00a789, + 0x00a78a, 0x00ab5b, 0x00ab5b, 0x00ab6a, 0x00ab6b, 0x00fbb2, 0x00fbc2, 0x00ff3e, 0x00ff3e, 0x00ff40, 0x00ff40, 0x00ffe3, 0x00ffe3, 0x01f3fb, 0x01f3ff)); } private static void populateGC_SM() { @@ -3097,16 +3163,17 @@ private static void populateGC_SO() { 0x0027bf, 0x002800, 0x0028ff, 0x002b00, 0x002b2f, 0x002b45, 0x002b46, 0x002b4d, 0x002b73, 0x002b76, 0x002b95, 0x002b97, 0x002bff, 0x002ce5, 0x002cea, 0x002e50, 0x002e51, 0x002e80, 0x002e99, 0x002e9b, 0x002ef3, 0x002f00, 0x002fd5, 0x002ff0, 0x002ffb, 0x003004, 0x003004, 0x003012, 0x003013, 0x003020, 0x003020, 0x003036, 0x003037, 0x00303e, 0x00303f, 0x003190, 0x003191, 0x003196, 0x00319f, 0x0031c0, 0x0031e3, 0x003200, 0x00321e, 0x00322a, 0x003247, 0x003250, 0x003250, 0x003260, 0x00327f, 0x00328a, 0x0032b0, - 0x0032c0, 0x0033ff, 0x004dc0, 0x004dff, 0x00a490, 0x00a4c6, 0x00a828, 0x00a82b, 0x00a836, 0x00a837, 0x00a839, 0x00a839, 0x00aa77, 0x00aa79, 0x00fdfd, 0x00fdfd, 0x00ffe4, - 0x00ffe4, 0x00ffe8, 0x00ffe8, 0x00ffed, 0x00ffee, 0x00fffc, 0x00fffd, 0x010137, 0x01013f, 0x010179, 0x010189, 0x01018c, 0x01018e, 0x010190, 0x01019c, 0x0101a0, 0x0101a0, - 0x0101d0, 0x0101fc, 0x010877, 0x010878, 0x010ac8, 0x010ac8, 0x01173f, 0x01173f, 0x011fd5, 0x011fdc, 0x011fe1, 0x011ff1, 0x016b3c, 0x016b3f, 0x016b45, 0x016b45, 0x01bc9c, - 0x01bc9c, 0x01d000, 0x01d0f5, 0x01d100, 0x01d126, 0x01d129, 0x01d164, 0x01d16a, 0x01d16c, 0x01d183, 0x01d184, 0x01d18c, 0x01d1a9, 0x01d1ae, 0x01d1e8, 0x01d200, 0x01d241, - 0x01d245, 0x01d245, 0x01d300, 0x01d356, 0x01d800, 0x01d9ff, 0x01da37, 0x01da3a, 0x01da6d, 0x01da74, 0x01da76, 0x01da83, 0x01da85, 0x01da86, 0x01e14f, 0x01e14f, 0x01ecac, - 0x01ecac, 0x01ed2e, 0x01ed2e, 0x01f000, 0x01f02b, 0x01f030, 0x01f093, 0x01f0a0, 0x01f0ae, 0x01f0b1, 0x01f0bf, 0x01f0c1, 0x01f0cf, 0x01f0d1, 0x01f0f5, 0x01f10d, 0x01f1ad, - 0x01f1e6, 0x01f202, 0x01f210, 0x01f23b, 0x01f240, 0x01f248, 0x01f250, 0x01f251, 0x01f260, 0x01f265, 0x01f300, 0x01f3fa, 0x01f400, 0x01f6d7, 0x01f6e0, 0x01f6ec, 0x01f6f0, - 0x01f6fc, 0x01f700, 0x01f773, 0x01f780, 0x01f7d8, 0x01f7e0, 0x01f7eb, 0x01f800, 0x01f80b, 0x01f810, 0x01f847, 0x01f850, 0x01f859, 0x01f860, 0x01f887, 0x01f890, 0x01f8ad, - 0x01f8b0, 0x01f8b1, 0x01f900, 0x01f978, 0x01f97a, 0x01f9cb, 0x01f9cd, 0x01fa53, 0x01fa60, 0x01fa6d, 0x01fa70, 0x01fa74, 0x01fa78, 0x01fa7a, 0x01fa80, 0x01fa86, 0x01fa90, - 0x01faa8, 0x01fab0, 0x01fab6, 0x01fac0, 0x01fac2, 0x01fad0, 0x01fad6, 0x01fb00, 0x01fb92, 0x01fb94, 0x01fbca)); + 0x0032c0, 0x0033ff, 0x004dc0, 0x004dff, 0x00a490, 0x00a4c6, 0x00a828, 0x00a82b, 0x00a836, 0x00a837, 0x00a839, 0x00a839, 0x00aa77, 0x00aa79, 0x00fd40, 0x00fd4f, 0x00fdcf, + 0x00fdcf, 0x00fdfd, 0x00fdff, 0x00ffe4, 0x00ffe4, 0x00ffe8, 0x00ffe8, 0x00ffed, 0x00ffee, 0x00fffc, 0x00fffd, 0x010137, 0x01013f, 0x010179, 0x010189, 0x01018c, 0x01018e, + 0x010190, 0x01019c, 0x0101a0, 0x0101a0, 0x0101d0, 0x0101fc, 0x010877, 0x010878, 0x010ac8, 0x010ac8, 0x01173f, 0x01173f, 0x011fd5, 0x011fdc, 0x011fe1, 0x011ff1, 0x016b3c, + 0x016b3f, 0x016b45, 0x016b45, 0x01bc9c, 0x01bc9c, 0x01cf50, 0x01cfc3, 0x01d000, 0x01d0f5, 0x01d100, 0x01d126, 0x01d129, 0x01d164, 0x01d16a, 0x01d16c, 0x01d183, 0x01d184, + 0x01d18c, 0x01d1a9, 0x01d1ae, 0x01d1ea, 0x01d200, 0x01d241, 0x01d245, 0x01d245, 0x01d300, 0x01d356, 0x01d800, 0x01d9ff, 0x01da37, 0x01da3a, 0x01da6d, 0x01da74, 0x01da76, + 0x01da83, 0x01da85, 0x01da86, 0x01e14f, 0x01e14f, 0x01ecac, 0x01ecac, 0x01ed2e, 0x01ed2e, 0x01f000, 0x01f02b, 0x01f030, 0x01f093, 0x01f0a0, 0x01f0ae, 0x01f0b1, 0x01f0bf, + 0x01f0c1, 0x01f0cf, 0x01f0d1, 0x01f0f5, 0x01f10d, 0x01f1ad, 0x01f1e6, 0x01f202, 0x01f210, 0x01f23b, 0x01f240, 0x01f248, 0x01f250, 0x01f251, 0x01f260, 0x01f265, 0x01f300, + 0x01f3fa, 0x01f400, 0x01f6d7, 0x01f6dd, 0x01f6ec, 0x01f6f0, 0x01f6fc, 0x01f700, 0x01f773, 0x01f780, 0x01f7d8, 0x01f7e0, 0x01f7eb, 0x01f7f0, 0x01f7f0, 0x01f800, 0x01f80b, + 0x01f810, 0x01f847, 0x01f850, 0x01f859, 0x01f860, 0x01f887, 0x01f890, 0x01f8ad, 0x01f8b0, 0x01f8b1, 0x01f900, 0x01fa53, 0x01fa60, 0x01fa6d, 0x01fa70, 0x01fa74, 0x01fa78, + 0x01fa7c, 0x01fa80, 0x01fa86, 0x01fa90, 0x01faac, 0x01fab0, 0x01faba, 0x01fac0, 0x01fac5, 0x01fad0, 0x01fad9, 0x01fae0, 0x01fae7, 0x01faf0, 0x01faf6, 0x01fb00, 0x01fb92, + 0x01fb94, 0x01fbca)); } private static void populateGC_ZL() { @@ -3131,13 +3198,13 @@ private static void populateSC_AGHB() { } private static void populateSC_AHOM() { - SET_ENCODINGS.put("sc=Ahom", CodePointSet.createNoDedup(0x011700, 0x01171a, 0x01171d, 0x01172b, 0x011730, 0x01173f)); + SET_ENCODINGS.put("sc=Ahom", CodePointSet.createNoDedup(0x011700, 0x01171a, 0x01171d, 0x01172b, 0x011730, 0x011746)); } private static void populateSC_ARAB() { - SET_ENCODINGS.put("sc=Arab", CodePointSet.createNoDedup(0x000600, 0x000604, 0x000606, 0x00060b, 0x00060d, 0x00061a, 0x00061c, 0x00061c, 0x00061e, 0x00061e, 0x000620, 0x00063f, 0x000641, - 0x00064a, 0x000656, 0x00066f, 0x000671, 0x0006dc, 0x0006de, 0x0006ff, 0x000750, 0x00077f, 0x0008a0, 0x0008b4, 0x0008b6, 0x0008c7, 0x0008d3, 0x0008e1, 0x0008e3, 0x0008ff, - 0x00fb50, 0x00fbc1, 0x00fbd3, 0x00fd3d, 0x00fd50, 0x00fd8f, 0x00fd92, 0x00fdc7, 0x00fdf0, 0x00fdfd, 0x00fe70, 0x00fe74, 0x00fe76, 0x00fefc, 0x010e60, 0x010e7e, 0x01ee00, + SET_ENCODINGS.put("sc=Arab", CodePointSet.createNoDedup(0x000600, 0x000604, 0x000606, 0x00060b, 0x00060d, 0x00061a, 0x00061c, 0x00061e, 0x000620, 0x00063f, 0x000641, 0x00064a, 0x000656, + 0x00066f, 0x000671, 0x0006dc, 0x0006de, 0x0006ff, 0x000750, 0x00077f, 0x000870, 0x00088e, 0x000890, 0x000891, 0x000898, 0x0008e1, 0x0008e3, 0x0008ff, 0x00fb50, 0x00fbc2, + 0x00fbd3, 0x00fd3d, 0x00fd40, 0x00fd8f, 0x00fd92, 0x00fdc7, 0x00fdcf, 0x00fdcf, 0x00fdf0, 0x00fdff, 0x00fe70, 0x00fe74, 0x00fe76, 0x00fefc, 0x010e60, 0x010e7e, 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, 0x01ee39, 0x01ee3b, 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, 0x01ee4d, 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, 0x01ee57, 0x01ee57, 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, 0x01ee72, 0x01ee74, 0x01ee77, @@ -3157,7 +3224,7 @@ private static void populateSC_AVST() { } private static void populateSC_BALI() { - SET_ENCODINGS.put("sc=Bali", CodePointSet.createNoDedup(0x001b00, 0x001b4b, 0x001b50, 0x001b7c)); + SET_ENCODINGS.put("sc=Bali", CodePointSet.createNoDedup(0x001b00, 0x001b4c, 0x001b50, 0x001b7e)); } private static void populateSC_BAMU() { @@ -3186,7 +3253,7 @@ private static void populateSC_BOPO() { } private static void populateSC_BRAH() { - SET_ENCODINGS.put("sc=Brah", CodePointSet.createNoDedup(0x011000, 0x01104d, 0x011052, 0x01106f, 0x01107f, 0x01107f)); + SET_ENCODINGS.put("sc=Brah", CodePointSet.createNoDedup(0x011000, 0x01104d, 0x011052, 0x011075, 0x01107f, 0x01107f)); } private static void populateSC_BRAI() { @@ -3206,7 +3273,7 @@ private static void populateSC_CAKM() { } private static void populateSC_CANS() { - SET_ENCODINGS.put("sc=Cans", CodePointSet.createNoDedup(0x001400, 0x00167f, 0x0018b0, 0x0018f5)); + SET_ENCODINGS.put("sc=Cans", CodePointSet.createNoDedup(0x001400, 0x00167f, 0x0018b0, 0x0018f5, 0x011ab0, 0x011abf)); } private static void populateSC_CARI() { @@ -3229,6 +3296,10 @@ private static void populateSC_COPT() { SET_ENCODINGS.put("sc=Copt", CodePointSet.createNoDedup(0x0003e2, 0x0003ef, 0x002c80, 0x002cf3, 0x002cf9, 0x002cff)); } + private static void populateSC_CPMN() { + SET_ENCODINGS.put("sc=Cpmn", CodePointSet.createNoDedup(0x012f90, 0x012ff2)); + } + private static void populateSC_CPRT() { SET_ENCODINGS.put("sc=Cprt", CodePointSet.createNoDedup(0x010800, 0x010805, 0x010808, 0x010808, 0x01080a, 0x010835, 0x010837, 0x010838, 0x01083c, 0x01083c, 0x01083f, 0x01083f)); } @@ -3272,10 +3343,12 @@ private static void populateSC_ELYM() { } private static void populateSC_ETHI() { - SET_ENCODINGS.put("sc=Ethi", CodePointSet.createNoDedup(0x001200, 0x001248, 0x00124a, 0x00124d, 0x001250, 0x001256, 0x001258, 0x001258, 0x00125a, 0x00125d, 0x001260, 0x001288, 0x00128a, - 0x00128d, 0x001290, 0x0012b0, 0x0012b2, 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, 0x0012d8, 0x001310, 0x001312, 0x001315, - 0x001318, 0x00135a, 0x00135d, 0x00137c, 0x001380, 0x001399, 0x002d80, 0x002d96, 0x002da0, 0x002da6, 0x002da8, 0x002dae, 0x002db0, 0x002db6, 0x002db8, 0x002dbe, 0x002dc0, - 0x002dc6, 0x002dc8, 0x002dce, 0x002dd0, 0x002dd6, 0x002dd8, 0x002dde, 0x00ab01, 0x00ab06, 0x00ab09, 0x00ab0e, 0x00ab11, 0x00ab16, 0x00ab20, 0x00ab26, 0x00ab28, 0x00ab2e)); + SET_ENCODINGS.put("sc=Ethi", + CodePointSet.createNoDedup(0x001200, 0x001248, 0x00124a, 0x00124d, 0x001250, 0x001256, 0x001258, 0x001258, 0x00125a, 0x00125d, 0x001260, 0x001288, 0x00128a, 0x00128d, 0x001290, + 0x0012b0, 0x0012b2, 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, 0x0012d8, 0x001310, 0x001312, 0x001315, 0x001318, + 0x00135a, 0x00135d, 0x00137c, 0x001380, 0x001399, 0x002d80, 0x002d96, 0x002da0, 0x002da6, 0x002da8, 0x002dae, 0x002db0, 0x002db6, 0x002db8, 0x002dbe, 0x002dc0, + 0x002dc6, 0x002dc8, 0x002dce, 0x002dd0, 0x002dd6, 0x002dd8, 0x002dde, 0x00ab01, 0x00ab06, 0x00ab09, 0x00ab0e, 0x00ab11, 0x00ab16, 0x00ab20, 0x00ab26, 0x00ab28, + 0x00ab2e, 0x01e7e0, 0x01e7e6, 0x01e7e8, 0x01e7eb, 0x01e7ed, 0x01e7ee, 0x01e7f0, 0x01e7fe)); } private static void populateSC_GEOR() { @@ -3284,8 +3357,7 @@ private static void populateSC_GEOR() { } private static void populateSC_GLAG() { - SET_ENCODINGS.put("sc=Glag", - CodePointSet.createNoDedup(0x002c00, 0x002c2e, 0x002c30, 0x002c5e, 0x01e000, 0x01e006, 0x01e008, 0x01e018, 0x01e01b, 0x01e021, 0x01e023, 0x01e024, 0x01e026, 0x01e02a)); + SET_ENCODINGS.put("sc=Glag", CodePointSet.createNoDedup(0x002c00, 0x002c5f, 0x01e000, 0x01e006, 0x01e008, 0x01e018, 0x01e01b, 0x01e021, 0x01e023, 0x01e024, 0x01e026, 0x01e02a)); } private static void populateSC_GONG() { @@ -3335,8 +3407,8 @@ private static void populateSC_HANG() { private static void populateSC_HANI() { SET_ENCODINGS.put("sc=Hani", CodePointSet.createNoDedup(0x002e80, 0x002e99, 0x002e9b, 0x002ef3, 0x002f00, 0x002fd5, 0x003005, 0x003005, 0x003007, 0x003007, 0x003021, 0x003029, 0x003038, 0x00303b, 0x003400, - 0x004dbf, 0x004e00, 0x009ffc, 0x00f900, 0x00fa6d, 0x00fa70, 0x00fad9, 0x016ff0, 0x016ff1, 0x020000, 0x02a6dd, 0x02a700, 0x02b734, 0x02b740, 0x02b81d, 0x02b820, - 0x02cea1, 0x02ceb0, 0x02ebe0, 0x02f800, 0x02fa1d, 0x030000, 0x03134a)); + 0x004dbf, 0x004e00, 0x009fff, 0x00f900, 0x00fa6d, 0x00fa70, 0x00fad9, 0x016fe2, 0x016fe3, 0x016ff0, 0x016ff1, 0x020000, 0x02a6df, 0x02a700, 0x02b738, 0x02b740, + 0x02b81d, 0x02b820, 0x02cea1, 0x02ceb0, 0x02ebe0, 0x02f800, 0x02fa1d, 0x030000, 0x03134a)); } private static void populateSC_HANO() { @@ -3353,7 +3425,7 @@ private static void populateSC_HEBR() { } private static void populateSC_HIRA() { - SET_ENCODINGS.put("sc=Hira", CodePointSet.createNoDedup(0x003041, 0x003096, 0x00309d, 0x00309f, 0x01b001, 0x01b11e, 0x01b150, 0x01b152, 0x01f200, 0x01f200)); + SET_ENCODINGS.put("sc=Hira", CodePointSet.createNoDedup(0x003041, 0x003096, 0x00309d, 0x00309f, 0x01b001, 0x01b11f, 0x01b150, 0x01b152, 0x01f200, 0x01f200)); } private static void populateSC_HLUW() { @@ -3386,7 +3458,7 @@ private static void populateSC_KALI() { private static void populateSC_KANA() { SET_ENCODINGS.put("sc=Kana", CodePointSet.createNoDedup(0x0030a1, 0x0030fa, 0x0030fd, 0x0030ff, 0x0031f0, 0x0031ff, 0x0032d0, 0x0032fe, 0x003300, 0x003357, 0x00ff66, 0x00ff6f, 0x00ff71, - 0x00ff9d, 0x01b000, 0x01b000, 0x01b164, 0x01b167)); + 0x00ff9d, 0x01aff0, 0x01aff3, 0x01aff5, 0x01affb, 0x01affd, 0x01affe, 0x01b000, 0x01b000, 0x01b120, 0x01b122, 0x01b164, 0x01b167)); } private static void populateSC_KHAR() { @@ -3408,11 +3480,11 @@ private static void populateSC_KITS() { private static void populateSC_KNDA() { SET_ENCODINGS.put("sc=Knda", CodePointSet.createNoDedup(0x000c80, 0x000c8c, 0x000c8e, 0x000c90, 0x000c92, 0x000ca8, 0x000caa, 0x000cb3, 0x000cb5, 0x000cb9, 0x000cbc, 0x000cc4, 0x000cc6, - 0x000cc8, 0x000cca, 0x000ccd, 0x000cd5, 0x000cd6, 0x000cde, 0x000cde, 0x000ce0, 0x000ce3, 0x000ce6, 0x000cef, 0x000cf1, 0x000cf2)); + 0x000cc8, 0x000cca, 0x000ccd, 0x000cd5, 0x000cd6, 0x000cdd, 0x000cde, 0x000ce0, 0x000ce3, 0x000ce6, 0x000cef, 0x000cf1, 0x000cf2)); } private static void populateSC_KTHI() { - SET_ENCODINGS.put("sc=Kthi", CodePointSet.createNoDedup(0x011080, 0x0110c1, 0x0110cd, 0x0110cd)); + SET_ENCODINGS.put("sc=Kthi", CodePointSet.createNoDedup(0x011080, 0x0110c2, 0x0110cd, 0x0110cd)); } private static void populateSC_LANA() { @@ -3425,10 +3497,12 @@ private static void populateSC_LAOO() { } private static void populateSC_LATN() { - SET_ENCODINGS.put("sc=Latn", CodePointSet.createNoDedup(0x000041, 0x00005a, 0x000061, 0x00007a, 0x0000aa, 0x0000aa, 0x0000ba, 0x0000ba, 0x0000c0, 0x0000d6, 0x0000d8, 0x0000f6, 0x0000f8, - 0x0002b8, 0x0002e0, 0x0002e4, 0x001d00, 0x001d25, 0x001d2c, 0x001d5c, 0x001d62, 0x001d65, 0x001d6b, 0x001d77, 0x001d79, 0x001dbe, 0x001e00, 0x001eff, 0x002071, 0x002071, - 0x00207f, 0x00207f, 0x002090, 0x00209c, 0x00212a, 0x00212b, 0x002132, 0x002132, 0x00214e, 0x00214e, 0x002160, 0x002188, 0x002c60, 0x002c7f, 0x00a722, 0x00a787, 0x00a78b, - 0x00a7bf, 0x00a7c2, 0x00a7ca, 0x00a7f5, 0x00a7ff, 0x00ab30, 0x00ab5a, 0x00ab5c, 0x00ab64, 0x00ab66, 0x00ab69, 0x00fb00, 0x00fb06, 0x00ff21, 0x00ff3a, 0x00ff41, 0x00ff5a)); + SET_ENCODINGS.put("sc=Latn", + CodePointSet.createNoDedup(0x000041, 0x00005a, 0x000061, 0x00007a, 0x0000aa, 0x0000aa, 0x0000ba, 0x0000ba, 0x0000c0, 0x0000d6, 0x0000d8, 0x0000f6, 0x0000f8, 0x0002b8, 0x0002e0, + 0x0002e4, 0x001d00, 0x001d25, 0x001d2c, 0x001d5c, 0x001d62, 0x001d65, 0x001d6b, 0x001d77, 0x001d79, 0x001dbe, 0x001e00, 0x001eff, 0x002071, 0x002071, 0x00207f, + 0x00207f, 0x002090, 0x00209c, 0x00212a, 0x00212b, 0x002132, 0x002132, 0x00214e, 0x00214e, 0x002160, 0x002188, 0x002c60, 0x002c7f, 0x00a722, 0x00a787, 0x00a78b, + 0x00a7ca, 0x00a7d0, 0x00a7d1, 0x00a7d3, 0x00a7d3, 0x00a7d5, 0x00a7d9, 0x00a7f2, 0x00a7ff, 0x00ab30, 0x00ab5a, 0x00ab5c, 0x00ab64, 0x00ab66, 0x00ab69, 0x00fb00, + 0x00fb06, 0x00ff21, 0x00ff3a, 0x00ff41, 0x00ff5a, 0x010780, 0x010785, 0x010787, 0x0107b0, 0x0107b2, 0x0107ba, 0x01df00, 0x01df1e)); } private static void populateSC_LEPC() { @@ -3506,8 +3580,7 @@ private static void populateSC_MODI() { } private static void populateSC_MONG() { - SET_ENCODINGS.put("sc=Mong", - CodePointSet.createNoDedup(0x001800, 0x001801, 0x001804, 0x001804, 0x001806, 0x00180e, 0x001810, 0x001819, 0x001820, 0x001878, 0x001880, 0x0018aa, 0x011660, 0x01166c)); + SET_ENCODINGS.put("sc=Mong", CodePointSet.createNoDedup(0x001800, 0x001801, 0x001804, 0x001804, 0x001806, 0x001819, 0x001820, 0x001878, 0x001880, 0x0018aa, 0x011660, 0x01166c)); } private static void populateSC_MROO() { @@ -3575,6 +3648,10 @@ private static void populateSC_OSMA() { SET_ENCODINGS.put("sc=Osma", CodePointSet.createNoDedup(0x010480, 0x01049d, 0x0104a0, 0x0104a9)); } + private static void populateSC_OUGR() { + SET_ENCODINGS.put("sc=Ougr", CodePointSet.createNoDedup(0x010f70, 0x010f89)); + } + private static void populateSC_PALM() { SET_ENCODINGS.put("sc=Palm", CodePointSet.createNoDedup(0x010860, 0x01087f)); } @@ -3693,7 +3770,7 @@ private static void populateSC_TAGB() { } private static void populateSC_TAKR() { - SET_ENCODINGS.put("sc=Takr", CodePointSet.createNoDedup(0x011680, 0x0116b8, 0x0116c0, 0x0116c9)); + SET_ENCODINGS.put("sc=Takr", CodePointSet.createNoDedup(0x011680, 0x0116b9, 0x0116c0, 0x0116c9)); } private static void populateSC_TALE() { @@ -3720,8 +3797,8 @@ private static void populateSC_TAVT() { } private static void populateSC_TELU() { - SET_ENCODINGS.put("sc=Telu", CodePointSet.createNoDedup(0x000c00, 0x000c0c, 0x000c0e, 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3d, 0x000c44, 0x000c46, 0x000c48, 0x000c4a, - 0x000c4d, 0x000c55, 0x000c56, 0x000c58, 0x000c5a, 0x000c60, 0x000c63, 0x000c66, 0x000c6f, 0x000c77, 0x000c7f)); + SET_ENCODINGS.put("sc=Telu", CodePointSet.createNoDedup(0x000c00, 0x000c0c, 0x000c0e, 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3c, 0x000c44, 0x000c46, 0x000c48, 0x000c4a, + 0x000c4d, 0x000c55, 0x000c56, 0x000c58, 0x000c5a, 0x000c5d, 0x000c5d, 0x000c60, 0x000c63, 0x000c66, 0x000c6f, 0x000c77, 0x000c7f)); } private static void populateSC_TFNG() { @@ -3729,7 +3806,7 @@ private static void populateSC_TFNG() { } private static void populateSC_TGLG() { - SET_ENCODINGS.put("sc=Tglg", CodePointSet.createNoDedup(0x001700, 0x00170c, 0x00170e, 0x001714)); + SET_ENCODINGS.put("sc=Tglg", CodePointSet.createNoDedup(0x001700, 0x001715, 0x00171f, 0x00171f)); } private static void populateSC_THAA() { @@ -3749,6 +3826,14 @@ private static void populateSC_TIRH() { SET_ENCODINGS.put("sc=Tirh", CodePointSet.createNoDedup(0x011480, 0x0114c7, 0x0114d0, 0x0114d9)); } + private static void populateSC_TNSA() { + SET_ENCODINGS.put("sc=Tnsa", CodePointSet.createNoDedup(0x016a70, 0x016abe, 0x016ac0, 0x016ac9)); + } + + private static void populateSC_TOTO() { + SET_ENCODINGS.put("sc=Toto", CodePointSet.createNoDedup(0x01e290, 0x01e2ae)); + } + private static void populateSC_UGAR() { SET_ENCODINGS.put("sc=Ugar", CodePointSet.createNoDedup(0x010380, 0x01039d, 0x01039f, 0x01039f)); } @@ -3757,6 +3842,11 @@ private static void populateSC_VAII() { SET_ENCODINGS.put("sc=Vaii", CodePointSet.createNoDedup(0x00a500, 0x00a62b)); } + private static void populateSC_VITH() { + SET_ENCODINGS.put("sc=Vith", CodePointSet.createNoDedup(0x010570, 0x01057a, 0x01057c, 0x01058a, 0x01058c, 0x010592, 0x010594, 0x010595, 0x010597, 0x0105a1, 0x0105a3, 0x0105b1, 0x0105b3, + 0x0105b9, 0x0105bb, 0x0105bc)); + } + private static void populateSC_WARA() { SET_ENCODINGS.put("sc=Wara", CodePointSet.createNoDedup(0x0118a0, 0x0118f2, 0x0118ff, 0x0118ff)); } @@ -3787,10 +3877,10 @@ private static void populateSC_ZANB() { private static void populateSC_ZINH() { SET_ENCODINGS.put("sc=Zinh", - CodePointSet.createNoDedup(0x000300, 0x00036f, 0x000485, 0x000486, 0x00064b, 0x000655, 0x000670, 0x000670, 0x000951, 0x000954, 0x001ab0, 0x001ac0, 0x001cd0, 0x001cd2, 0x001cd4, - 0x001ce0, 0x001ce2, 0x001ce8, 0x001ced, 0x001ced, 0x001cf4, 0x001cf4, 0x001cf8, 0x001cf9, 0x001dc0, 0x001df9, 0x001dfb, 0x001dff, 0x00200c, 0x00200d, 0x0020d0, - 0x0020f0, 0x00302a, 0x00302d, 0x003099, 0x00309a, 0x00fe00, 0x00fe0f, 0x00fe20, 0x00fe2d, 0x0101fd, 0x0101fd, 0x0102e0, 0x0102e0, 0x01133b, 0x01133b, 0x01d167, - 0x01d169, 0x01d17b, 0x01d182, 0x01d185, 0x01d18b, 0x01d1aa, 0x01d1ad, 0x0e0100, 0x0e01ef)); + CodePointSet.createNoDedup(0x000300, 0x00036f, 0x000485, 0x000486, 0x00064b, 0x000655, 0x000670, 0x000670, 0x000951, 0x000954, 0x001ab0, 0x001ace, 0x001cd0, 0x001cd2, 0x001cd4, + 0x001ce0, 0x001ce2, 0x001ce8, 0x001ced, 0x001ced, 0x001cf4, 0x001cf4, 0x001cf8, 0x001cf9, 0x001dc0, 0x001dff, 0x00200c, 0x00200d, 0x0020d0, 0x0020f0, 0x00302a, + 0x00302d, 0x003099, 0x00309a, 0x00fe00, 0x00fe0f, 0x00fe20, 0x00fe2d, 0x0101fd, 0x0101fd, 0x0102e0, 0x0102e0, 0x01133b, 0x01133b, 0x01cf00, 0x01cf2d, 0x01cf30, + 0x01cf46, 0x01d167, 0x01d169, 0x01d17b, 0x01d182, 0x01d185, 0x01d18b, 0x01d1aa, 0x01d1ad, 0x0e0100, 0x0e01ef)); } private static void populateSC_ZYYY() { @@ -3799,40 +3889,40 @@ private static void populateSC_ZYYY() { 0x00060c, 0x00060c, 0x00061b, 0x00061b, 0x00061f, 0x00061f, 0x000640, 0x000640, 0x0006dd, 0x0006dd, 0x0008e2, 0x0008e2, 0x000964, 0x000965, 0x000e3f, 0x000e3f, 0x000fd5, 0x000fd8, 0x0010fb, 0x0010fb, 0x0016eb, 0x0016ed, 0x001735, 0x001736, 0x001802, 0x001803, 0x001805, 0x001805, 0x001cd3, 0x001cd3, 0x001ce1, 0x001ce1, 0x001ce9, 0x001cec, 0x001cee, 0x001cf3, 0x001cf5, 0x001cf7, 0x001cfa, 0x001cfa, 0x002000, 0x00200b, 0x00200e, 0x002064, 0x002066, 0x002070, 0x002074, 0x00207e, 0x002080, 0x00208e, 0x0020a0, - 0x0020bf, 0x002100, 0x002125, 0x002127, 0x002129, 0x00212c, 0x002131, 0x002133, 0x00214d, 0x00214f, 0x00215f, 0x002189, 0x00218b, 0x002190, 0x002426, 0x002440, 0x00244a, - 0x002460, 0x0027ff, 0x002900, 0x002b73, 0x002b76, 0x002b95, 0x002b97, 0x002bff, 0x002e00, 0x002e52, 0x002ff0, 0x002ffb, 0x003000, 0x003004, 0x003006, 0x003006, 0x003008, + 0x0020c0, 0x002100, 0x002125, 0x002127, 0x002129, 0x00212c, 0x002131, 0x002133, 0x00214d, 0x00214f, 0x00215f, 0x002189, 0x00218b, 0x002190, 0x002426, 0x002440, 0x00244a, + 0x002460, 0x0027ff, 0x002900, 0x002b73, 0x002b76, 0x002b95, 0x002b97, 0x002bff, 0x002e00, 0x002e5d, 0x002ff0, 0x002ffb, 0x003000, 0x003004, 0x003006, 0x003006, 0x003008, 0x003020, 0x003030, 0x003037, 0x00303c, 0x00303f, 0x00309b, 0x00309c, 0x0030a0, 0x0030a0, 0x0030fb, 0x0030fc, 0x003190, 0x00319f, 0x0031c0, 0x0031e3, 0x003220, 0x00325f, 0x00327f, 0x0032cf, 0x0032ff, 0x0032ff, 0x003358, 0x0033ff, 0x004dc0, 0x004dff, 0x00a700, 0x00a721, 0x00a788, 0x00a78a, 0x00a830, 0x00a839, 0x00a92e, 0x00a92e, 0x00a9cf, 0x00a9cf, 0x00ab5b, 0x00ab5b, 0x00ab6a, 0x00ab6b, 0x00fd3e, 0x00fd3f, 0x00fe10, 0x00fe19, 0x00fe30, 0x00fe52, 0x00fe54, 0x00fe66, 0x00fe68, 0x00fe6b, 0x00feff, 0x00feff, 0x00ff01, 0x00ff20, 0x00ff3b, 0x00ff40, 0x00ff5b, 0x00ff65, 0x00ff70, 0x00ff70, 0x00ff9e, 0x00ff9f, 0x00ffe0, 0x00ffe6, 0x00ffe8, 0x00ffee, 0x00fff9, 0x00fffd, 0x010100, - 0x010102, 0x010107, 0x010133, 0x010137, 0x01013f, 0x010190, 0x01019c, 0x0101d0, 0x0101fc, 0x0102e1, 0x0102fb, 0x016fe2, 0x016fe3, 0x01bca0, 0x01bca3, 0x01d000, 0x01d0f5, - 0x01d100, 0x01d126, 0x01d129, 0x01d166, 0x01d16a, 0x01d17a, 0x01d183, 0x01d184, 0x01d18c, 0x01d1a9, 0x01d1ae, 0x01d1e8, 0x01d2e0, 0x01d2f3, 0x01d300, 0x01d356, 0x01d360, + 0x010102, 0x010107, 0x010133, 0x010137, 0x01013f, 0x010190, 0x01019c, 0x0101d0, 0x0101fc, 0x0102e1, 0x0102fb, 0x01bca0, 0x01bca3, 0x01cf50, 0x01cfc3, 0x01d000, 0x01d0f5, + 0x01d100, 0x01d126, 0x01d129, 0x01d166, 0x01d16a, 0x01d17a, 0x01d183, 0x01d184, 0x01d18c, 0x01d1a9, 0x01d1ae, 0x01d1ea, 0x01d2e0, 0x01d2f3, 0x01d300, 0x01d356, 0x01d360, 0x01d378, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d7cb, 0x01d7ce, 0x01d7ff, 0x01ec71, 0x01ecb4, 0x01ed01, 0x01ed3d, 0x01f000, 0x01f02b, 0x01f030, 0x01f093, 0x01f0a0, 0x01f0ae, 0x01f0b1, 0x01f0bf, 0x01f0c1, 0x01f0cf, 0x01f0d1, 0x01f0f5, 0x01f100, 0x01f1ad, 0x01f1e6, 0x01f1ff, 0x01f201, 0x01f202, 0x01f210, 0x01f23b, 0x01f240, - 0x01f248, 0x01f250, 0x01f251, 0x01f260, 0x01f265, 0x01f300, 0x01f6d7, 0x01f6e0, 0x01f6ec, 0x01f6f0, 0x01f6fc, 0x01f700, 0x01f773, 0x01f780, 0x01f7d8, 0x01f7e0, 0x01f7eb, - 0x01f800, 0x01f80b, 0x01f810, 0x01f847, 0x01f850, 0x01f859, 0x01f860, 0x01f887, 0x01f890, 0x01f8ad, 0x01f8b0, 0x01f8b1, 0x01f900, 0x01f978, 0x01f97a, 0x01f9cb, 0x01f9cd, - 0x01fa53, 0x01fa60, 0x01fa6d, 0x01fa70, 0x01fa74, 0x01fa78, 0x01fa7a, 0x01fa80, 0x01fa86, 0x01fa90, 0x01faa8, 0x01fab0, 0x01fab6, 0x01fac0, 0x01fac2, 0x01fad0, 0x01fad6, - 0x01fb00, 0x01fb92, 0x01fb94, 0x01fbca, 0x01fbf0, 0x01fbf9, 0x0e0001, 0x0e0001, 0x0e0020, 0x0e007f)); + 0x01f248, 0x01f250, 0x01f251, 0x01f260, 0x01f265, 0x01f300, 0x01f6d7, 0x01f6dd, 0x01f6ec, 0x01f6f0, 0x01f6fc, 0x01f700, 0x01f773, 0x01f780, 0x01f7d8, 0x01f7e0, 0x01f7eb, + 0x01f7f0, 0x01f7f0, 0x01f800, 0x01f80b, 0x01f810, 0x01f847, 0x01f850, 0x01f859, 0x01f860, 0x01f887, 0x01f890, 0x01f8ad, 0x01f8b0, 0x01f8b1, 0x01f900, 0x01fa53, 0x01fa60, + 0x01fa6d, 0x01fa70, 0x01fa74, 0x01fa78, 0x01fa7c, 0x01fa80, 0x01fa86, 0x01fa90, 0x01faac, 0x01fab0, 0x01faba, 0x01fac0, 0x01fac5, 0x01fad0, 0x01fad9, 0x01fae0, 0x01fae7, + 0x01faf0, 0x01faf6, 0x01fb00, 0x01fb92, 0x01fb94, 0x01fbca, 0x01fbf0, 0x01fbf9, 0x0e0001, 0x0e0001, 0x0e0020, 0x0e007f)); } private static void populateSC_ZZZZ() { SET_ENCODINGS.put("sc=Zzzz", CodePointSet.createNoDedup(0x000378, 0x000379, 0x000380, 0x000383, 0x00038b, 0x00038b, 0x00038d, 0x00038d, 0x0003a2, 0x0003a2, 0x000530, 0x000530, 0x000557, - 0x000558, 0x00058b, 0x00058c, 0x000590, 0x000590, 0x0005c8, 0x0005cf, 0x0005eb, 0x0005ee, 0x0005f5, 0x0005ff, 0x00061d, 0x00061d, 0x00070e, 0x00070e, 0x00074b, 0x00074c, - 0x0007b2, 0x0007bf, 0x0007fb, 0x0007fc, 0x00082e, 0x00082f, 0x00083f, 0x00083f, 0x00085c, 0x00085d, 0x00085f, 0x00085f, 0x00086b, 0x00089f, 0x0008b5, 0x0008b5, 0x0008c8, - 0x0008d2, 0x000984, 0x000984, 0x00098d, 0x00098e, 0x000991, 0x000992, 0x0009a9, 0x0009a9, 0x0009b1, 0x0009b1, 0x0009b3, 0x0009b5, 0x0009ba, 0x0009bb, 0x0009c5, 0x0009c6, - 0x0009c9, 0x0009ca, 0x0009cf, 0x0009d6, 0x0009d8, 0x0009db, 0x0009de, 0x0009de, 0x0009e4, 0x0009e5, 0x0009ff, 0x000a00, 0x000a04, 0x000a04, 0x000a0b, 0x000a0e, 0x000a11, - 0x000a12, 0x000a29, 0x000a29, 0x000a31, 0x000a31, 0x000a34, 0x000a34, 0x000a37, 0x000a37, 0x000a3a, 0x000a3b, 0x000a3d, 0x000a3d, 0x000a43, 0x000a46, 0x000a49, 0x000a4a, - 0x000a4e, 0x000a50, 0x000a52, 0x000a58, 0x000a5d, 0x000a5d, 0x000a5f, 0x000a65, 0x000a77, 0x000a80, 0x000a84, 0x000a84, 0x000a8e, 0x000a8e, 0x000a92, 0x000a92, 0x000aa9, - 0x000aa9, 0x000ab1, 0x000ab1, 0x000ab4, 0x000ab4, 0x000aba, 0x000abb, 0x000ac6, 0x000ac6, 0x000aca, 0x000aca, 0x000ace, 0x000acf, 0x000ad1, 0x000adf, 0x000ae4, 0x000ae5, - 0x000af2, 0x000af8, 0x000b00, 0x000b00, 0x000b04, 0x000b04, 0x000b0d, 0x000b0e, 0x000b11, 0x000b12, 0x000b29, 0x000b29, 0x000b31, 0x000b31, 0x000b34, 0x000b34, 0x000b3a, - 0x000b3b, 0x000b45, 0x000b46, 0x000b49, 0x000b4a, 0x000b4e, 0x000b54, 0x000b58, 0x000b5b, 0x000b5e, 0x000b5e, 0x000b64, 0x000b65, 0x000b78, 0x000b81, 0x000b84, 0x000b84, - 0x000b8b, 0x000b8d, 0x000b91, 0x000b91, 0x000b96, 0x000b98, 0x000b9b, 0x000b9b, 0x000b9d, 0x000b9d, 0x000ba0, 0x000ba2, 0x000ba5, 0x000ba7, 0x000bab, 0x000bad, 0x000bba, - 0x000bbd, 0x000bc3, 0x000bc5, 0x000bc9, 0x000bc9, 0x000bce, 0x000bcf, 0x000bd1, 0x000bd6, 0x000bd8, 0x000be5, 0x000bfb, 0x000bff, 0x000c0d, 0x000c0d, 0x000c11, 0x000c11, - 0x000c29, 0x000c29, 0x000c3a, 0x000c3c, 0x000c45, 0x000c45, 0x000c49, 0x000c49, 0x000c4e, 0x000c54, 0x000c57, 0x000c57, 0x000c5b, 0x000c5f, 0x000c64, 0x000c65, 0x000c70, + 0x000558, 0x00058b, 0x00058c, 0x000590, 0x000590, 0x0005c8, 0x0005cf, 0x0005eb, 0x0005ee, 0x0005f5, 0x0005ff, 0x00070e, 0x00070e, 0x00074b, 0x00074c, 0x0007b2, 0x0007bf, + 0x0007fb, 0x0007fc, 0x00082e, 0x00082f, 0x00083f, 0x00083f, 0x00085c, 0x00085d, 0x00085f, 0x00085f, 0x00086b, 0x00086f, 0x00088f, 0x00088f, 0x000892, 0x000897, 0x000984, + 0x000984, 0x00098d, 0x00098e, 0x000991, 0x000992, 0x0009a9, 0x0009a9, 0x0009b1, 0x0009b1, 0x0009b3, 0x0009b5, 0x0009ba, 0x0009bb, 0x0009c5, 0x0009c6, 0x0009c9, 0x0009ca, + 0x0009cf, 0x0009d6, 0x0009d8, 0x0009db, 0x0009de, 0x0009de, 0x0009e4, 0x0009e5, 0x0009ff, 0x000a00, 0x000a04, 0x000a04, 0x000a0b, 0x000a0e, 0x000a11, 0x000a12, 0x000a29, + 0x000a29, 0x000a31, 0x000a31, 0x000a34, 0x000a34, 0x000a37, 0x000a37, 0x000a3a, 0x000a3b, 0x000a3d, 0x000a3d, 0x000a43, 0x000a46, 0x000a49, 0x000a4a, 0x000a4e, 0x000a50, + 0x000a52, 0x000a58, 0x000a5d, 0x000a5d, 0x000a5f, 0x000a65, 0x000a77, 0x000a80, 0x000a84, 0x000a84, 0x000a8e, 0x000a8e, 0x000a92, 0x000a92, 0x000aa9, 0x000aa9, 0x000ab1, + 0x000ab1, 0x000ab4, 0x000ab4, 0x000aba, 0x000abb, 0x000ac6, 0x000ac6, 0x000aca, 0x000aca, 0x000ace, 0x000acf, 0x000ad1, 0x000adf, 0x000ae4, 0x000ae5, 0x000af2, 0x000af8, + 0x000b00, 0x000b00, 0x000b04, 0x000b04, 0x000b0d, 0x000b0e, 0x000b11, 0x000b12, 0x000b29, 0x000b29, 0x000b31, 0x000b31, 0x000b34, 0x000b34, 0x000b3a, 0x000b3b, 0x000b45, + 0x000b46, 0x000b49, 0x000b4a, 0x000b4e, 0x000b54, 0x000b58, 0x000b5b, 0x000b5e, 0x000b5e, 0x000b64, 0x000b65, 0x000b78, 0x000b81, 0x000b84, 0x000b84, 0x000b8b, 0x000b8d, + 0x000b91, 0x000b91, 0x000b96, 0x000b98, 0x000b9b, 0x000b9b, 0x000b9d, 0x000b9d, 0x000ba0, 0x000ba2, 0x000ba5, 0x000ba7, 0x000bab, 0x000bad, 0x000bba, 0x000bbd, 0x000bc3, + 0x000bc5, 0x000bc9, 0x000bc9, 0x000bce, 0x000bcf, 0x000bd1, 0x000bd6, 0x000bd8, 0x000be5, 0x000bfb, 0x000bff, 0x000c0d, 0x000c0d, 0x000c11, 0x000c11, 0x000c29, 0x000c29, + 0x000c3a, 0x000c3b, 0x000c45, 0x000c45, 0x000c49, 0x000c49, 0x000c4e, 0x000c54, 0x000c57, 0x000c57, 0x000c5b, 0x000c5c, 0x000c5e, 0x000c5f, 0x000c64, 0x000c65, 0x000c70, 0x000c76, 0x000c8d, 0x000c8d, 0x000c91, 0x000c91, 0x000ca9, 0x000ca9, 0x000cb4, 0x000cb4, 0x000cba, 0x000cbb, 0x000cc5, 0x000cc5, 0x000cc9, 0x000cc9, 0x000cce, 0x000cd4, - 0x000cd7, 0x000cdd, 0x000cdf, 0x000cdf, 0x000ce4, 0x000ce5, 0x000cf0, 0x000cf0, 0x000cf3, 0x000cff, 0x000d0d, 0x000d0d, 0x000d11, 0x000d11, 0x000d45, 0x000d45, 0x000d49, + 0x000cd7, 0x000cdc, 0x000cdf, 0x000cdf, 0x000ce4, 0x000ce5, 0x000cf0, 0x000cf0, 0x000cf3, 0x000cff, 0x000d0d, 0x000d0d, 0x000d11, 0x000d11, 0x000d45, 0x000d45, 0x000d49, 0x000d49, 0x000d50, 0x000d53, 0x000d64, 0x000d65, 0x000d80, 0x000d80, 0x000d84, 0x000d84, 0x000d97, 0x000d99, 0x000db2, 0x000db2, 0x000dbc, 0x000dbc, 0x000dbe, 0x000dbf, 0x000dc7, 0x000dc9, 0x000dcb, 0x000dce, 0x000dd5, 0x000dd5, 0x000dd7, 0x000dd7, 0x000de0, 0x000de5, 0x000df0, 0x000df1, 0x000df5, 0x000e00, 0x000e3b, 0x000e3e, 0x000e5c, 0x000e80, 0x000e83, 0x000e83, 0x000e85, 0x000e85, 0x000e8b, 0x000e8b, 0x000ea4, 0x000ea4, 0x000ea6, 0x000ea6, 0x000ebe, 0x000ebf, 0x000ec5, 0x000ec5, 0x000ec7, 0x000ec7, @@ -3840,68 +3930,71 @@ private static void populateSC_ZZZZ() { 0x000fff, 0x0010c6, 0x0010c6, 0x0010c8, 0x0010cc, 0x0010ce, 0x0010cf, 0x001249, 0x001249, 0x00124e, 0x00124f, 0x001257, 0x001257, 0x001259, 0x001259, 0x00125e, 0x00125f, 0x001289, 0x001289, 0x00128e, 0x00128f, 0x0012b1, 0x0012b1, 0x0012b6, 0x0012b7, 0x0012bf, 0x0012bf, 0x0012c1, 0x0012c1, 0x0012c6, 0x0012c7, 0x0012d7, 0x0012d7, 0x001311, 0x001311, 0x001316, 0x001317, 0x00135b, 0x00135c, 0x00137d, 0x00137f, 0x00139a, 0x00139f, 0x0013f6, 0x0013f7, 0x0013fe, 0x0013ff, 0x00169d, 0x00169f, 0x0016f9, 0x0016ff, - 0x00170d, 0x00170d, 0x001715, 0x00171f, 0x001737, 0x00173f, 0x001754, 0x00175f, 0x00176d, 0x00176d, 0x001771, 0x001771, 0x001774, 0x00177f, 0x0017de, 0x0017df, 0x0017ea, - 0x0017ef, 0x0017fa, 0x0017ff, 0x00180f, 0x00180f, 0x00181a, 0x00181f, 0x001879, 0x00187f, 0x0018ab, 0x0018af, 0x0018f6, 0x0018ff, 0x00191f, 0x00191f, 0x00192c, 0x00192f, - 0x00193c, 0x00193f, 0x001941, 0x001943, 0x00196e, 0x00196f, 0x001975, 0x00197f, 0x0019ac, 0x0019af, 0x0019ca, 0x0019cf, 0x0019db, 0x0019dd, 0x001a1c, 0x001a1d, 0x001a5f, - 0x001a5f, 0x001a7d, 0x001a7e, 0x001a8a, 0x001a8f, 0x001a9a, 0x001a9f, 0x001aae, 0x001aaf, 0x001ac1, 0x001aff, 0x001b4c, 0x001b4f, 0x001b7d, 0x001b7f, 0x001bf4, 0x001bfb, - 0x001c38, 0x001c3a, 0x001c4a, 0x001c4c, 0x001c89, 0x001c8f, 0x001cbb, 0x001cbc, 0x001cc8, 0x001ccf, 0x001cfb, 0x001cff, 0x001dfa, 0x001dfa, 0x001f16, 0x001f17, 0x001f1e, - 0x001f1f, 0x001f46, 0x001f47, 0x001f4e, 0x001f4f, 0x001f58, 0x001f58, 0x001f5a, 0x001f5a, 0x001f5c, 0x001f5c, 0x001f5e, 0x001f5e, 0x001f7e, 0x001f7f, 0x001fb5, 0x001fb5, - 0x001fc5, 0x001fc5, 0x001fd4, 0x001fd5, 0x001fdc, 0x001fdc, 0x001ff0, 0x001ff1, 0x001ff5, 0x001ff5, 0x001fff, 0x001fff, 0x002065, 0x002065, 0x002072, 0x002073, 0x00208f, - 0x00208f, 0x00209d, 0x00209f, 0x0020c0, 0x0020cf, 0x0020f1, 0x0020ff, 0x00218c, 0x00218f, 0x002427, 0x00243f, 0x00244b, 0x00245f, 0x002b74, 0x002b75, 0x002b96, 0x002b96, - 0x002c2f, 0x002c2f, 0x002c5f, 0x002c5f, 0x002cf4, 0x002cf8, 0x002d26, 0x002d26, 0x002d28, 0x002d2c, 0x002d2e, 0x002d2f, 0x002d68, 0x002d6e, 0x002d71, 0x002d7e, 0x002d97, - 0x002d9f, 0x002da7, 0x002da7, 0x002daf, 0x002daf, 0x002db7, 0x002db7, 0x002dbf, 0x002dbf, 0x002dc7, 0x002dc7, 0x002dcf, 0x002dcf, 0x002dd7, 0x002dd7, 0x002ddf, 0x002ddf, - 0x002e53, 0x002e7f, 0x002e9a, 0x002e9a, 0x002ef4, 0x002eff, 0x002fd6, 0x002fef, 0x002ffc, 0x002fff, 0x003040, 0x003040, 0x003097, 0x003098, 0x003100, 0x003104, 0x003130, - 0x003130, 0x00318f, 0x00318f, 0x0031e4, 0x0031ef, 0x00321f, 0x00321f, 0x009ffd, 0x009fff, 0x00a48d, 0x00a48f, 0x00a4c7, 0x00a4cf, 0x00a62c, 0x00a63f, 0x00a6f8, 0x00a6ff, - 0x00a7c0, 0x00a7c1, 0x00a7cb, 0x00a7f4, 0x00a82d, 0x00a82f, 0x00a83a, 0x00a83f, 0x00a878, 0x00a87f, 0x00a8c6, 0x00a8cd, 0x00a8da, 0x00a8df, 0x00a954, 0x00a95e, 0x00a97d, - 0x00a97f, 0x00a9ce, 0x00a9ce, 0x00a9da, 0x00a9dd, 0x00a9ff, 0x00a9ff, 0x00aa37, 0x00aa3f, 0x00aa4e, 0x00aa4f, 0x00aa5a, 0x00aa5b, 0x00aac3, 0x00aada, 0x00aaf7, 0x00ab00, - 0x00ab07, 0x00ab08, 0x00ab0f, 0x00ab10, 0x00ab17, 0x00ab1f, 0x00ab27, 0x00ab27, 0x00ab2f, 0x00ab2f, 0x00ab6c, 0x00ab6f, 0x00abee, 0x00abef, 0x00abfa, 0x00abff, 0x00d7a4, - 0x00d7af, 0x00d7c7, 0x00d7ca, 0x00d7fc, 0x00f8ff, 0x00fa6e, 0x00fa6f, 0x00fada, 0x00faff, 0x00fb07, 0x00fb12, 0x00fb18, 0x00fb1c, 0x00fb37, 0x00fb37, 0x00fb3d, 0x00fb3d, - 0x00fb3f, 0x00fb3f, 0x00fb42, 0x00fb42, 0x00fb45, 0x00fb45, 0x00fbc2, 0x00fbd2, 0x00fd40, 0x00fd4f, 0x00fd90, 0x00fd91, 0x00fdc8, 0x00fdef, 0x00fdfe, 0x00fdff, 0x00fe1a, - 0x00fe1f, 0x00fe53, 0x00fe53, 0x00fe67, 0x00fe67, 0x00fe6c, 0x00fe6f, 0x00fe75, 0x00fe75, 0x00fefd, 0x00fefe, 0x00ff00, 0x00ff00, 0x00ffbf, 0x00ffc1, 0x00ffc8, 0x00ffc9, - 0x00ffd0, 0x00ffd1, 0x00ffd8, 0x00ffd9, 0x00ffdd, 0x00ffdf, 0x00ffe7, 0x00ffe7, 0x00ffef, 0x00fff8, 0x00fffe, 0x00ffff, 0x01000c, 0x01000c, 0x010027, 0x010027, 0x01003b, - 0x01003b, 0x01003e, 0x01003e, 0x01004e, 0x01004f, 0x01005e, 0x01007f, 0x0100fb, 0x0100ff, 0x010103, 0x010106, 0x010134, 0x010136, 0x01018f, 0x01018f, 0x01019d, 0x01019f, - 0x0101a1, 0x0101cf, 0x0101fe, 0x01027f, 0x01029d, 0x01029f, 0x0102d1, 0x0102df, 0x0102fc, 0x0102ff, 0x010324, 0x01032c, 0x01034b, 0x01034f, 0x01037b, 0x01037f, 0x01039e, - 0x01039e, 0x0103c4, 0x0103c7, 0x0103d6, 0x0103ff, 0x01049e, 0x01049f, 0x0104aa, 0x0104af, 0x0104d4, 0x0104d7, 0x0104fc, 0x0104ff, 0x010528, 0x01052f, 0x010564, 0x01056e, - 0x010570, 0x0105ff, 0x010737, 0x01073f, 0x010756, 0x01075f, 0x010768, 0x0107ff, 0x010806, 0x010807, 0x010809, 0x010809, 0x010836, 0x010836, 0x010839, 0x01083b, 0x01083d, - 0x01083e, 0x010856, 0x010856, 0x01089f, 0x0108a6, 0x0108b0, 0x0108df, 0x0108f3, 0x0108f3, 0x0108f6, 0x0108fa, 0x01091c, 0x01091e, 0x01093a, 0x01093e, 0x010940, 0x01097f, - 0x0109b8, 0x0109bb, 0x0109d0, 0x0109d1, 0x010a04, 0x010a04, 0x010a07, 0x010a0b, 0x010a14, 0x010a14, 0x010a18, 0x010a18, 0x010a36, 0x010a37, 0x010a3b, 0x010a3e, 0x010a49, - 0x010a4f, 0x010a59, 0x010a5f, 0x010aa0, 0x010abf, 0x010ae7, 0x010aea, 0x010af7, 0x010aff, 0x010b36, 0x010b38, 0x010b56, 0x010b57, 0x010b73, 0x010b77, 0x010b92, 0x010b98, - 0x010b9d, 0x010ba8, 0x010bb0, 0x010bff, 0x010c49, 0x010c7f, 0x010cb3, 0x010cbf, 0x010cf3, 0x010cf9, 0x010d28, 0x010d2f, 0x010d3a, 0x010e5f, 0x010e7f, 0x010e7f, 0x010eaa, - 0x010eaa, 0x010eae, 0x010eaf, 0x010eb2, 0x010eff, 0x010f28, 0x010f2f, 0x010f5a, 0x010faf, 0x010fcc, 0x010fdf, 0x010ff7, 0x010fff, 0x01104e, 0x011051, 0x011070, 0x01107e, - 0x0110c2, 0x0110cc, 0x0110ce, 0x0110cf, 0x0110e9, 0x0110ef, 0x0110fa, 0x0110ff, 0x011135, 0x011135, 0x011148, 0x01114f, 0x011177, 0x01117f, 0x0111e0, 0x0111e0, 0x0111f5, - 0x0111ff, 0x011212, 0x011212, 0x01123f, 0x01127f, 0x011287, 0x011287, 0x011289, 0x011289, 0x01128e, 0x01128e, 0x01129e, 0x01129e, 0x0112aa, 0x0112af, 0x0112eb, 0x0112ef, - 0x0112fa, 0x0112ff, 0x011304, 0x011304, 0x01130d, 0x01130e, 0x011311, 0x011312, 0x011329, 0x011329, 0x011331, 0x011331, 0x011334, 0x011334, 0x01133a, 0x01133a, 0x011345, - 0x011346, 0x011349, 0x01134a, 0x01134e, 0x01134f, 0x011351, 0x011356, 0x011358, 0x01135c, 0x011364, 0x011365, 0x01136d, 0x01136f, 0x011375, 0x0113ff, 0x01145c, 0x01145c, - 0x011462, 0x01147f, 0x0114c8, 0x0114cf, 0x0114da, 0x01157f, 0x0115b6, 0x0115b7, 0x0115de, 0x0115ff, 0x011645, 0x01164f, 0x01165a, 0x01165f, 0x01166d, 0x01167f, 0x0116b9, - 0x0116bf, 0x0116ca, 0x0116ff, 0x01171b, 0x01171c, 0x01172c, 0x01172f, 0x011740, 0x0117ff, 0x01183c, 0x01189f, 0x0118f3, 0x0118fe, 0x011907, 0x011908, 0x01190a, 0x01190b, - 0x011914, 0x011914, 0x011917, 0x011917, 0x011936, 0x011936, 0x011939, 0x01193a, 0x011947, 0x01194f, 0x01195a, 0x01199f, 0x0119a8, 0x0119a9, 0x0119d8, 0x0119d9, 0x0119e5, - 0x0119ff, 0x011a48, 0x011a4f, 0x011aa3, 0x011abf, 0x011af9, 0x011bff, 0x011c09, 0x011c09, 0x011c37, 0x011c37, 0x011c46, 0x011c4f, 0x011c6d, 0x011c6f, 0x011c90, 0x011c91, - 0x011ca8, 0x011ca8, 0x011cb7, 0x011cff, 0x011d07, 0x011d07, 0x011d0a, 0x011d0a, 0x011d37, 0x011d39, 0x011d3b, 0x011d3b, 0x011d3e, 0x011d3e, 0x011d48, 0x011d4f, 0x011d5a, - 0x011d5f, 0x011d66, 0x011d66, 0x011d69, 0x011d69, 0x011d8f, 0x011d8f, 0x011d92, 0x011d92, 0x011d99, 0x011d9f, 0x011daa, 0x011edf, 0x011ef9, 0x011faf, 0x011fb1, 0x011fbf, - 0x011ff2, 0x011ffe, 0x01239a, 0x0123ff, 0x01246f, 0x01246f, 0x012475, 0x01247f, 0x012544, 0x012fff, 0x01342f, 0x01342f, 0x013439, 0x0143ff, 0x014647, 0x0167ff, 0x016a39, - 0x016a3f, 0x016a5f, 0x016a5f, 0x016a6a, 0x016a6d, 0x016a70, 0x016acf, 0x016aee, 0x016aef, 0x016af6, 0x016aff, 0x016b46, 0x016b4f, 0x016b5a, 0x016b5a, 0x016b62, 0x016b62, - 0x016b78, 0x016b7c, 0x016b90, 0x016e3f, 0x016e9b, 0x016eff, 0x016f4b, 0x016f4e, 0x016f88, 0x016f8e, 0x016fa0, 0x016fdf, 0x016fe5, 0x016fef, 0x016ff2, 0x016fff, 0x0187f8, - 0x0187ff, 0x018cd6, 0x018cff, 0x018d09, 0x01afff, 0x01b11f, 0x01b14f, 0x01b153, 0x01b163, 0x01b168, 0x01b16f, 0x01b2fc, 0x01bbff, 0x01bc6b, 0x01bc6f, 0x01bc7d, 0x01bc7f, - 0x01bc89, 0x01bc8f, 0x01bc9a, 0x01bc9b, 0x01bca4, 0x01cfff, 0x01d0f6, 0x01d0ff, 0x01d127, 0x01d128, 0x01d1e9, 0x01d1ff, 0x01d246, 0x01d2df, 0x01d2f4, 0x01d2ff, 0x01d357, - 0x01d35f, 0x01d379, 0x01d3ff, 0x01d455, 0x01d455, 0x01d49d, 0x01d49d, 0x01d4a0, 0x01d4a1, 0x01d4a3, 0x01d4a4, 0x01d4a7, 0x01d4a8, 0x01d4ad, 0x01d4ad, 0x01d4ba, 0x01d4ba, - 0x01d4bc, 0x01d4bc, 0x01d4c4, 0x01d4c4, 0x01d506, 0x01d506, 0x01d50b, 0x01d50c, 0x01d515, 0x01d515, 0x01d51d, 0x01d51d, 0x01d53a, 0x01d53a, 0x01d53f, 0x01d53f, 0x01d545, - 0x01d545, 0x01d547, 0x01d549, 0x01d551, 0x01d551, 0x01d6a6, 0x01d6a7, 0x01d7cc, 0x01d7cd, 0x01da8c, 0x01da9a, 0x01daa0, 0x01daa0, 0x01dab0, 0x01dfff, 0x01e007, 0x01e007, - 0x01e019, 0x01e01a, 0x01e022, 0x01e022, 0x01e025, 0x01e025, 0x01e02b, 0x01e0ff, 0x01e12d, 0x01e12f, 0x01e13e, 0x01e13f, 0x01e14a, 0x01e14d, 0x01e150, 0x01e2bf, 0x01e2fa, - 0x01e2fe, 0x01e300, 0x01e7ff, 0x01e8c5, 0x01e8c6, 0x01e8d7, 0x01e8ff, 0x01e94c, 0x01e94f, 0x01e95a, 0x01e95d, 0x01e960, 0x01ec70, 0x01ecb5, 0x01ed00, 0x01ed3e, 0x01edff, - 0x01ee04, 0x01ee04, 0x01ee20, 0x01ee20, 0x01ee23, 0x01ee23, 0x01ee25, 0x01ee26, 0x01ee28, 0x01ee28, 0x01ee33, 0x01ee33, 0x01ee38, 0x01ee38, 0x01ee3a, 0x01ee3a, 0x01ee3c, - 0x01ee41, 0x01ee43, 0x01ee46, 0x01ee48, 0x01ee48, 0x01ee4a, 0x01ee4a, 0x01ee4c, 0x01ee4c, 0x01ee50, 0x01ee50, 0x01ee53, 0x01ee53, 0x01ee55, 0x01ee56, 0x01ee58, 0x01ee58, - 0x01ee5a, 0x01ee5a, 0x01ee5c, 0x01ee5c, 0x01ee5e, 0x01ee5e, 0x01ee60, 0x01ee60, 0x01ee63, 0x01ee63, 0x01ee65, 0x01ee66, 0x01ee6b, 0x01ee6b, 0x01ee73, 0x01ee73, 0x01ee78, - 0x01ee78, 0x01ee7d, 0x01ee7d, 0x01ee7f, 0x01ee7f, 0x01ee8a, 0x01ee8a, 0x01ee9c, 0x01eea0, 0x01eea4, 0x01eea4, 0x01eeaa, 0x01eeaa, 0x01eebc, 0x01eeef, 0x01eef2, 0x01efff, - 0x01f02c, 0x01f02f, 0x01f094, 0x01f09f, 0x01f0af, 0x01f0b0, 0x01f0c0, 0x01f0c0, 0x01f0d0, 0x01f0d0, 0x01f0f6, 0x01f0ff, 0x01f1ae, 0x01f1e5, 0x01f203, 0x01f20f, 0x01f23c, - 0x01f23f, 0x01f249, 0x01f24f, 0x01f252, 0x01f25f, 0x01f266, 0x01f2ff, 0x01f6d8, 0x01f6df, 0x01f6ed, 0x01f6ef, 0x01f6fd, 0x01f6ff, 0x01f774, 0x01f77f, 0x01f7d9, 0x01f7df, - 0x01f7ec, 0x01f7ff, 0x01f80c, 0x01f80f, 0x01f848, 0x01f84f, 0x01f85a, 0x01f85f, 0x01f888, 0x01f88f, 0x01f8ae, 0x01f8af, 0x01f8b2, 0x01f8ff, 0x01f979, 0x01f979, 0x01f9cc, - 0x01f9cc, 0x01fa54, 0x01fa5f, 0x01fa6e, 0x01fa6f, 0x01fa75, 0x01fa77, 0x01fa7b, 0x01fa7f, 0x01fa87, 0x01fa8f, 0x01faa9, 0x01faaf, 0x01fab7, 0x01fabf, 0x01fac3, 0x01facf, - 0x01fad7, 0x01faff, 0x01fb93, 0x01fb93, 0x01fbcb, 0x01fbef, 0x01fbfa, 0x01ffff, 0x02a6de, 0x02a6ff, 0x02b735, 0x02b73f, 0x02b81e, 0x02b81f, 0x02cea2, 0x02ceaf, 0x02ebe1, - 0x02f7ff, 0x02fa1e, 0x02ffff, 0x03134b, 0x0e0000, 0x0e0002, 0x0e001f, 0x0e0080, 0x0e00ff, 0x0e01f0, 0x10ffff)); + 0x001716, 0x00171e, 0x001737, 0x00173f, 0x001754, 0x00175f, 0x00176d, 0x00176d, 0x001771, 0x001771, 0x001774, 0x00177f, 0x0017de, 0x0017df, 0x0017ea, 0x0017ef, 0x0017fa, + 0x0017ff, 0x00181a, 0x00181f, 0x001879, 0x00187f, 0x0018ab, 0x0018af, 0x0018f6, 0x0018ff, 0x00191f, 0x00191f, 0x00192c, 0x00192f, 0x00193c, 0x00193f, 0x001941, 0x001943, + 0x00196e, 0x00196f, 0x001975, 0x00197f, 0x0019ac, 0x0019af, 0x0019ca, 0x0019cf, 0x0019db, 0x0019dd, 0x001a1c, 0x001a1d, 0x001a5f, 0x001a5f, 0x001a7d, 0x001a7e, 0x001a8a, + 0x001a8f, 0x001a9a, 0x001a9f, 0x001aae, 0x001aaf, 0x001acf, 0x001aff, 0x001b4d, 0x001b4f, 0x001b7f, 0x001b7f, 0x001bf4, 0x001bfb, 0x001c38, 0x001c3a, 0x001c4a, 0x001c4c, + 0x001c89, 0x001c8f, 0x001cbb, 0x001cbc, 0x001cc8, 0x001ccf, 0x001cfb, 0x001cff, 0x001f16, 0x001f17, 0x001f1e, 0x001f1f, 0x001f46, 0x001f47, 0x001f4e, 0x001f4f, 0x001f58, + 0x001f58, 0x001f5a, 0x001f5a, 0x001f5c, 0x001f5c, 0x001f5e, 0x001f5e, 0x001f7e, 0x001f7f, 0x001fb5, 0x001fb5, 0x001fc5, 0x001fc5, 0x001fd4, 0x001fd5, 0x001fdc, 0x001fdc, + 0x001ff0, 0x001ff1, 0x001ff5, 0x001ff5, 0x001fff, 0x001fff, 0x002065, 0x002065, 0x002072, 0x002073, 0x00208f, 0x00208f, 0x00209d, 0x00209f, 0x0020c1, 0x0020cf, 0x0020f1, + 0x0020ff, 0x00218c, 0x00218f, 0x002427, 0x00243f, 0x00244b, 0x00245f, 0x002b74, 0x002b75, 0x002b96, 0x002b96, 0x002cf4, 0x002cf8, 0x002d26, 0x002d26, 0x002d28, 0x002d2c, + 0x002d2e, 0x002d2f, 0x002d68, 0x002d6e, 0x002d71, 0x002d7e, 0x002d97, 0x002d9f, 0x002da7, 0x002da7, 0x002daf, 0x002daf, 0x002db7, 0x002db7, 0x002dbf, 0x002dbf, 0x002dc7, + 0x002dc7, 0x002dcf, 0x002dcf, 0x002dd7, 0x002dd7, 0x002ddf, 0x002ddf, 0x002e5e, 0x002e7f, 0x002e9a, 0x002e9a, 0x002ef4, 0x002eff, 0x002fd6, 0x002fef, 0x002ffc, 0x002fff, + 0x003040, 0x003040, 0x003097, 0x003098, 0x003100, 0x003104, 0x003130, 0x003130, 0x00318f, 0x00318f, 0x0031e4, 0x0031ef, 0x00321f, 0x00321f, 0x00a48d, 0x00a48f, 0x00a4c7, + 0x00a4cf, 0x00a62c, 0x00a63f, 0x00a6f8, 0x00a6ff, 0x00a7cb, 0x00a7cf, 0x00a7d2, 0x00a7d2, 0x00a7d4, 0x00a7d4, 0x00a7da, 0x00a7f1, 0x00a82d, 0x00a82f, 0x00a83a, 0x00a83f, + 0x00a878, 0x00a87f, 0x00a8c6, 0x00a8cd, 0x00a8da, 0x00a8df, 0x00a954, 0x00a95e, 0x00a97d, 0x00a97f, 0x00a9ce, 0x00a9ce, 0x00a9da, 0x00a9dd, 0x00a9ff, 0x00a9ff, 0x00aa37, + 0x00aa3f, 0x00aa4e, 0x00aa4f, 0x00aa5a, 0x00aa5b, 0x00aac3, 0x00aada, 0x00aaf7, 0x00ab00, 0x00ab07, 0x00ab08, 0x00ab0f, 0x00ab10, 0x00ab17, 0x00ab1f, 0x00ab27, 0x00ab27, + 0x00ab2f, 0x00ab2f, 0x00ab6c, 0x00ab6f, 0x00abee, 0x00abef, 0x00abfa, 0x00abff, 0x00d7a4, 0x00d7af, 0x00d7c7, 0x00d7ca, 0x00d7fc, 0x00f8ff, 0x00fa6e, 0x00fa6f, 0x00fada, + 0x00faff, 0x00fb07, 0x00fb12, 0x00fb18, 0x00fb1c, 0x00fb37, 0x00fb37, 0x00fb3d, 0x00fb3d, 0x00fb3f, 0x00fb3f, 0x00fb42, 0x00fb42, 0x00fb45, 0x00fb45, 0x00fbc3, 0x00fbd2, + 0x00fd90, 0x00fd91, 0x00fdc8, 0x00fdce, 0x00fdd0, 0x00fdef, 0x00fe1a, 0x00fe1f, 0x00fe53, 0x00fe53, 0x00fe67, 0x00fe67, 0x00fe6c, 0x00fe6f, 0x00fe75, 0x00fe75, 0x00fefd, + 0x00fefe, 0x00ff00, 0x00ff00, 0x00ffbf, 0x00ffc1, 0x00ffc8, 0x00ffc9, 0x00ffd0, 0x00ffd1, 0x00ffd8, 0x00ffd9, 0x00ffdd, 0x00ffdf, 0x00ffe7, 0x00ffe7, 0x00ffef, 0x00fff8, + 0x00fffe, 0x00ffff, 0x01000c, 0x01000c, 0x010027, 0x010027, 0x01003b, 0x01003b, 0x01003e, 0x01003e, 0x01004e, 0x01004f, 0x01005e, 0x01007f, 0x0100fb, 0x0100ff, 0x010103, + 0x010106, 0x010134, 0x010136, 0x01018f, 0x01018f, 0x01019d, 0x01019f, 0x0101a1, 0x0101cf, 0x0101fe, 0x01027f, 0x01029d, 0x01029f, 0x0102d1, 0x0102df, 0x0102fc, 0x0102ff, + 0x010324, 0x01032c, 0x01034b, 0x01034f, 0x01037b, 0x01037f, 0x01039e, 0x01039e, 0x0103c4, 0x0103c7, 0x0103d6, 0x0103ff, 0x01049e, 0x01049f, 0x0104aa, 0x0104af, 0x0104d4, + 0x0104d7, 0x0104fc, 0x0104ff, 0x010528, 0x01052f, 0x010564, 0x01056e, 0x01057b, 0x01057b, 0x01058b, 0x01058b, 0x010593, 0x010593, 0x010596, 0x010596, 0x0105a2, 0x0105a2, + 0x0105b2, 0x0105b2, 0x0105ba, 0x0105ba, 0x0105bd, 0x0105ff, 0x010737, 0x01073f, 0x010756, 0x01075f, 0x010768, 0x01077f, 0x010786, 0x010786, 0x0107b1, 0x0107b1, 0x0107bb, + 0x0107ff, 0x010806, 0x010807, 0x010809, 0x010809, 0x010836, 0x010836, 0x010839, 0x01083b, 0x01083d, 0x01083e, 0x010856, 0x010856, 0x01089f, 0x0108a6, 0x0108b0, 0x0108df, + 0x0108f3, 0x0108f3, 0x0108f6, 0x0108fa, 0x01091c, 0x01091e, 0x01093a, 0x01093e, 0x010940, 0x01097f, 0x0109b8, 0x0109bb, 0x0109d0, 0x0109d1, 0x010a04, 0x010a04, 0x010a07, + 0x010a0b, 0x010a14, 0x010a14, 0x010a18, 0x010a18, 0x010a36, 0x010a37, 0x010a3b, 0x010a3e, 0x010a49, 0x010a4f, 0x010a59, 0x010a5f, 0x010aa0, 0x010abf, 0x010ae7, 0x010aea, + 0x010af7, 0x010aff, 0x010b36, 0x010b38, 0x010b56, 0x010b57, 0x010b73, 0x010b77, 0x010b92, 0x010b98, 0x010b9d, 0x010ba8, 0x010bb0, 0x010bff, 0x010c49, 0x010c7f, 0x010cb3, + 0x010cbf, 0x010cf3, 0x010cf9, 0x010d28, 0x010d2f, 0x010d3a, 0x010e5f, 0x010e7f, 0x010e7f, 0x010eaa, 0x010eaa, 0x010eae, 0x010eaf, 0x010eb2, 0x010eff, 0x010f28, 0x010f2f, + 0x010f5a, 0x010f6f, 0x010f8a, 0x010faf, 0x010fcc, 0x010fdf, 0x010ff7, 0x010fff, 0x01104e, 0x011051, 0x011076, 0x01107e, 0x0110c3, 0x0110cc, 0x0110ce, 0x0110cf, 0x0110e9, + 0x0110ef, 0x0110fa, 0x0110ff, 0x011135, 0x011135, 0x011148, 0x01114f, 0x011177, 0x01117f, 0x0111e0, 0x0111e0, 0x0111f5, 0x0111ff, 0x011212, 0x011212, 0x01123f, 0x01127f, + 0x011287, 0x011287, 0x011289, 0x011289, 0x01128e, 0x01128e, 0x01129e, 0x01129e, 0x0112aa, 0x0112af, 0x0112eb, 0x0112ef, 0x0112fa, 0x0112ff, 0x011304, 0x011304, 0x01130d, + 0x01130e, 0x011311, 0x011312, 0x011329, 0x011329, 0x011331, 0x011331, 0x011334, 0x011334, 0x01133a, 0x01133a, 0x011345, 0x011346, 0x011349, 0x01134a, 0x01134e, 0x01134f, + 0x011351, 0x011356, 0x011358, 0x01135c, 0x011364, 0x011365, 0x01136d, 0x01136f, 0x011375, 0x0113ff, 0x01145c, 0x01145c, 0x011462, 0x01147f, 0x0114c8, 0x0114cf, 0x0114da, + 0x01157f, 0x0115b6, 0x0115b7, 0x0115de, 0x0115ff, 0x011645, 0x01164f, 0x01165a, 0x01165f, 0x01166d, 0x01167f, 0x0116ba, 0x0116bf, 0x0116ca, 0x0116ff, 0x01171b, 0x01171c, + 0x01172c, 0x01172f, 0x011747, 0x0117ff, 0x01183c, 0x01189f, 0x0118f3, 0x0118fe, 0x011907, 0x011908, 0x01190a, 0x01190b, 0x011914, 0x011914, 0x011917, 0x011917, 0x011936, + 0x011936, 0x011939, 0x01193a, 0x011947, 0x01194f, 0x01195a, 0x01199f, 0x0119a8, 0x0119a9, 0x0119d8, 0x0119d9, 0x0119e5, 0x0119ff, 0x011a48, 0x011a4f, 0x011aa3, 0x011aaf, + 0x011af9, 0x011bff, 0x011c09, 0x011c09, 0x011c37, 0x011c37, 0x011c46, 0x011c4f, 0x011c6d, 0x011c6f, 0x011c90, 0x011c91, 0x011ca8, 0x011ca8, 0x011cb7, 0x011cff, 0x011d07, + 0x011d07, 0x011d0a, 0x011d0a, 0x011d37, 0x011d39, 0x011d3b, 0x011d3b, 0x011d3e, 0x011d3e, 0x011d48, 0x011d4f, 0x011d5a, 0x011d5f, 0x011d66, 0x011d66, 0x011d69, 0x011d69, + 0x011d8f, 0x011d8f, 0x011d92, 0x011d92, 0x011d99, 0x011d9f, 0x011daa, 0x011edf, 0x011ef9, 0x011faf, 0x011fb1, 0x011fbf, 0x011ff2, 0x011ffe, 0x01239a, 0x0123ff, 0x01246f, + 0x01246f, 0x012475, 0x01247f, 0x012544, 0x012f8f, 0x012ff3, 0x012fff, 0x01342f, 0x01342f, 0x013439, 0x0143ff, 0x014647, 0x0167ff, 0x016a39, 0x016a3f, 0x016a5f, 0x016a5f, + 0x016a6a, 0x016a6d, 0x016abf, 0x016abf, 0x016aca, 0x016acf, 0x016aee, 0x016aef, 0x016af6, 0x016aff, 0x016b46, 0x016b4f, 0x016b5a, 0x016b5a, 0x016b62, 0x016b62, 0x016b78, + 0x016b7c, 0x016b90, 0x016e3f, 0x016e9b, 0x016eff, 0x016f4b, 0x016f4e, 0x016f88, 0x016f8e, 0x016fa0, 0x016fdf, 0x016fe5, 0x016fef, 0x016ff2, 0x016fff, 0x0187f8, 0x0187ff, + 0x018cd6, 0x018cff, 0x018d09, 0x01afef, 0x01aff4, 0x01aff4, 0x01affc, 0x01affc, 0x01afff, 0x01afff, 0x01b123, 0x01b14f, 0x01b153, 0x01b163, 0x01b168, 0x01b16f, 0x01b2fc, + 0x01bbff, 0x01bc6b, 0x01bc6f, 0x01bc7d, 0x01bc7f, 0x01bc89, 0x01bc8f, 0x01bc9a, 0x01bc9b, 0x01bca4, 0x01ceff, 0x01cf2e, 0x01cf2f, 0x01cf47, 0x01cf4f, 0x01cfc4, 0x01cfff, + 0x01d0f6, 0x01d0ff, 0x01d127, 0x01d128, 0x01d1eb, 0x01d1ff, 0x01d246, 0x01d2df, 0x01d2f4, 0x01d2ff, 0x01d357, 0x01d35f, 0x01d379, 0x01d3ff, 0x01d455, 0x01d455, 0x01d49d, + 0x01d49d, 0x01d4a0, 0x01d4a1, 0x01d4a3, 0x01d4a4, 0x01d4a7, 0x01d4a8, 0x01d4ad, 0x01d4ad, 0x01d4ba, 0x01d4ba, 0x01d4bc, 0x01d4bc, 0x01d4c4, 0x01d4c4, 0x01d506, 0x01d506, + 0x01d50b, 0x01d50c, 0x01d515, 0x01d515, 0x01d51d, 0x01d51d, 0x01d53a, 0x01d53a, 0x01d53f, 0x01d53f, 0x01d545, 0x01d545, 0x01d547, 0x01d549, 0x01d551, 0x01d551, 0x01d6a6, + 0x01d6a7, 0x01d7cc, 0x01d7cd, 0x01da8c, 0x01da9a, 0x01daa0, 0x01daa0, 0x01dab0, 0x01deff, 0x01df1f, 0x01dfff, 0x01e007, 0x01e007, 0x01e019, 0x01e01a, 0x01e022, 0x01e022, + 0x01e025, 0x01e025, 0x01e02b, 0x01e0ff, 0x01e12d, 0x01e12f, 0x01e13e, 0x01e13f, 0x01e14a, 0x01e14d, 0x01e150, 0x01e28f, 0x01e2af, 0x01e2bf, 0x01e2fa, 0x01e2fe, 0x01e300, + 0x01e7df, 0x01e7e7, 0x01e7e7, 0x01e7ec, 0x01e7ec, 0x01e7ef, 0x01e7ef, 0x01e7ff, 0x01e7ff, 0x01e8c5, 0x01e8c6, 0x01e8d7, 0x01e8ff, 0x01e94c, 0x01e94f, 0x01e95a, 0x01e95d, + 0x01e960, 0x01ec70, 0x01ecb5, 0x01ed00, 0x01ed3e, 0x01edff, 0x01ee04, 0x01ee04, 0x01ee20, 0x01ee20, 0x01ee23, 0x01ee23, 0x01ee25, 0x01ee26, 0x01ee28, 0x01ee28, 0x01ee33, + 0x01ee33, 0x01ee38, 0x01ee38, 0x01ee3a, 0x01ee3a, 0x01ee3c, 0x01ee41, 0x01ee43, 0x01ee46, 0x01ee48, 0x01ee48, 0x01ee4a, 0x01ee4a, 0x01ee4c, 0x01ee4c, 0x01ee50, 0x01ee50, + 0x01ee53, 0x01ee53, 0x01ee55, 0x01ee56, 0x01ee58, 0x01ee58, 0x01ee5a, 0x01ee5a, 0x01ee5c, 0x01ee5c, 0x01ee5e, 0x01ee5e, 0x01ee60, 0x01ee60, 0x01ee63, 0x01ee63, 0x01ee65, + 0x01ee66, 0x01ee6b, 0x01ee6b, 0x01ee73, 0x01ee73, 0x01ee78, 0x01ee78, 0x01ee7d, 0x01ee7d, 0x01ee7f, 0x01ee7f, 0x01ee8a, 0x01ee8a, 0x01ee9c, 0x01eea0, 0x01eea4, 0x01eea4, + 0x01eeaa, 0x01eeaa, 0x01eebc, 0x01eeef, 0x01eef2, 0x01efff, 0x01f02c, 0x01f02f, 0x01f094, 0x01f09f, 0x01f0af, 0x01f0b0, 0x01f0c0, 0x01f0c0, 0x01f0d0, 0x01f0d0, 0x01f0f6, + 0x01f0ff, 0x01f1ae, 0x01f1e5, 0x01f203, 0x01f20f, 0x01f23c, 0x01f23f, 0x01f249, 0x01f24f, 0x01f252, 0x01f25f, 0x01f266, 0x01f2ff, 0x01f6d8, 0x01f6dc, 0x01f6ed, 0x01f6ef, + 0x01f6fd, 0x01f6ff, 0x01f774, 0x01f77f, 0x01f7d9, 0x01f7df, 0x01f7ec, 0x01f7ef, 0x01f7f1, 0x01f7ff, 0x01f80c, 0x01f80f, 0x01f848, 0x01f84f, 0x01f85a, 0x01f85f, 0x01f888, + 0x01f88f, 0x01f8ae, 0x01f8af, 0x01f8b2, 0x01f8ff, 0x01fa54, 0x01fa5f, 0x01fa6e, 0x01fa6f, 0x01fa75, 0x01fa77, 0x01fa7d, 0x01fa7f, 0x01fa87, 0x01fa8f, 0x01faad, 0x01faaf, + 0x01fabb, 0x01fabf, 0x01fac6, 0x01facf, 0x01fada, 0x01fadf, 0x01fae8, 0x01faef, 0x01faf7, 0x01faff, 0x01fb93, 0x01fb93, 0x01fbcb, 0x01fbef, 0x01fbfa, 0x01ffff, 0x02a6e0, + 0x02a6ff, 0x02b739, 0x02b73f, 0x02b81e, 0x02b81f, 0x02cea2, 0x02ceaf, 0x02ebe1, 0x02f7ff, 0x02fa1e, 0x02ffff, 0x03134b, 0x0e0000, 0x0e0002, 0x0e001f, 0x0e0080, 0x0e00ff, + 0x0e01f0, 0x10ffff)); } private static void populateSCX_ADLM() { - SET_ENCODINGS.put("scx=Adlm", CodePointSet.createNoDedup(0x000640, 0x000640, 0x01e900, 0x01e94b, 0x01e950, 0x01e959, 0x01e95e, 0x01e95f)); + SET_ENCODINGS.put("scx=Adlm", CodePointSet.createNoDedup(0x00061f, 0x00061f, 0x000640, 0x000640, 0x01e900, 0x01e94b, 0x01e950, 0x01e959, 0x01e95e, 0x01e95f)); } private static void populateSCX_AGHB() { @@ -3909,18 +4002,18 @@ private static void populateSCX_AGHB() { } private static void populateSCX_AHOM() { - SET_ENCODINGS.put("scx=Ahom", CodePointSet.createNoDedup(0x011700, 0x01171a, 0x01171d, 0x01172b, 0x011730, 0x01173f)); + SET_ENCODINGS.put("scx=Ahom", CodePointSet.createNoDedup(0x011700, 0x01171a, 0x01171d, 0x01172b, 0x011730, 0x011746)); } private static void populateSCX_ARAB() { SET_ENCODINGS.put("scx=Arab", - CodePointSet.createNoDedup(0x000600, 0x000604, 0x000606, 0x00061c, 0x00061e, 0x0006dc, 0x0006de, 0x0006ff, 0x000750, 0x00077f, 0x0008a0, 0x0008b4, 0x0008b6, 0x0008c7, 0x0008d3, - 0x0008e1, 0x0008e3, 0x0008ff, 0x00fb50, 0x00fbc1, 0x00fbd3, 0x00fd3d, 0x00fd50, 0x00fd8f, 0x00fd92, 0x00fdc7, 0x00fdf0, 0x00fdfd, 0x00fe70, 0x00fe74, 0x00fe76, - 0x00fefc, 0x0102e0, 0x0102fb, 0x010e60, 0x010e7e, 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, 0x01ee27, 0x01ee29, - 0x01ee32, 0x01ee34, 0x01ee37, 0x01ee39, 0x01ee39, 0x01ee3b, 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, 0x01ee4d, - 0x01ee4f, 0x01ee51, 0x01ee52, 0x01ee54, 0x01ee54, 0x01ee57, 0x01ee57, 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, - 0x01ee62, 0x01ee64, 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, 0x01ee72, 0x01ee74, 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, 0x01ee80, 0x01ee89, 0x01ee8b, - 0x01ee9b, 0x01eea1, 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, 0x01eef0, 0x01eef1)); + CodePointSet.createNoDedup(0x000600, 0x000604, 0x000606, 0x0006dc, 0x0006de, 0x0006ff, 0x000750, 0x00077f, 0x000870, 0x00088e, 0x000890, 0x000891, 0x000898, 0x0008e1, 0x0008e3, + 0x0008ff, 0x00fb50, 0x00fbc2, 0x00fbd3, 0x00fd8f, 0x00fd92, 0x00fdc7, 0x00fdcf, 0x00fdcf, 0x00fdf0, 0x00fdff, 0x00fe70, 0x00fe74, 0x00fe76, 0x00fefc, 0x0102e0, + 0x0102fb, 0x010e60, 0x010e7e, 0x01ee00, 0x01ee03, 0x01ee05, 0x01ee1f, 0x01ee21, 0x01ee22, 0x01ee24, 0x01ee24, 0x01ee27, 0x01ee27, 0x01ee29, 0x01ee32, 0x01ee34, + 0x01ee37, 0x01ee39, 0x01ee39, 0x01ee3b, 0x01ee3b, 0x01ee42, 0x01ee42, 0x01ee47, 0x01ee47, 0x01ee49, 0x01ee49, 0x01ee4b, 0x01ee4b, 0x01ee4d, 0x01ee4f, 0x01ee51, + 0x01ee52, 0x01ee54, 0x01ee54, 0x01ee57, 0x01ee57, 0x01ee59, 0x01ee59, 0x01ee5b, 0x01ee5b, 0x01ee5d, 0x01ee5d, 0x01ee5f, 0x01ee5f, 0x01ee61, 0x01ee62, 0x01ee64, + 0x01ee64, 0x01ee67, 0x01ee6a, 0x01ee6c, 0x01ee72, 0x01ee74, 0x01ee77, 0x01ee79, 0x01ee7c, 0x01ee7e, 0x01ee7e, 0x01ee80, 0x01ee89, 0x01ee8b, 0x01ee9b, 0x01eea1, + 0x01eea3, 0x01eea5, 0x01eea9, 0x01eeab, 0x01eebb, 0x01eef0, 0x01eef1)); } private static void populateSCX_ARMI() { @@ -3936,7 +4029,7 @@ private static void populateSCX_AVST() { } private static void populateSCX_BALI() { - SET_ENCODINGS.put("scx=Bali", CodePointSet.createNoDedup(0x001b00, 0x001b4b, 0x001b50, 0x001b7c)); + SET_ENCODINGS.put("scx=Bali", CodePointSet.createNoDedup(0x001b00, 0x001b4c, 0x001b50, 0x001b7e)); } private static void populateSCX_BAMU() { @@ -3969,7 +4062,7 @@ private static void populateSCX_BOPO() { } private static void populateSCX_BRAH() { - SET_ENCODINGS.put("scx=Brah", CodePointSet.createNoDedup(0x011000, 0x01104d, 0x011052, 0x01106f, 0x01107f, 0x01107f)); + SET_ENCODINGS.put("scx=Brah", CodePointSet.createNoDedup(0x011000, 0x01104d, 0x011052, 0x011075, 0x01107f, 0x01107f)); } private static void populateSCX_BRAI() { @@ -3989,7 +4082,7 @@ private static void populateSCX_CAKM() { } private static void populateSCX_CANS() { - SET_ENCODINGS.put("scx=Cans", CodePointSet.createNoDedup(0x001400, 0x00167f, 0x0018b0, 0x0018f5)); + SET_ENCODINGS.put("scx=Cans", CodePointSet.createNoDedup(0x001400, 0x00167f, 0x0018b0, 0x0018f5, 0x011ab0, 0x011abf)); } private static void populateSCX_CARI() { @@ -4012,6 +4105,10 @@ private static void populateSCX_COPT() { SET_ENCODINGS.put("scx=Copt", CodePointSet.createNoDedup(0x0003e2, 0x0003ef, 0x002c80, 0x002cf3, 0x002cf9, 0x002cff, 0x0102e0, 0x0102fb)); } + private static void populateSCX_CPMN() { + SET_ENCODINGS.put("scx=Cpmn", CodePointSet.createNoDedup(0x010100, 0x010101, 0x012f90, 0x012ff2)); + } + private static void populateSCX_CPRT() { SET_ENCODINGS.put("scx=Cprt", CodePointSet.createNoDedup(0x010100, 0x010102, 0x010107, 0x010133, 0x010137, 0x01013f, 0x010800, 0x010805, 0x010808, 0x010808, 0x01080a, 0x010835, 0x010837, 0x010838, 0x01083c, 0x01083c, 0x01083f, 0x01083f)); @@ -4057,10 +4154,12 @@ private static void populateSCX_ELYM() { } private static void populateSCX_ETHI() { - SET_ENCODINGS.put("scx=Ethi", CodePointSet.createNoDedup(0x001200, 0x001248, 0x00124a, 0x00124d, 0x001250, 0x001256, 0x001258, 0x001258, 0x00125a, 0x00125d, 0x001260, 0x001288, 0x00128a, - 0x00128d, 0x001290, 0x0012b0, 0x0012b2, 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, 0x0012d8, 0x001310, 0x001312, 0x001315, - 0x001318, 0x00135a, 0x00135d, 0x00137c, 0x001380, 0x001399, 0x002d80, 0x002d96, 0x002da0, 0x002da6, 0x002da8, 0x002dae, 0x002db0, 0x002db6, 0x002db8, 0x002dbe, 0x002dc0, - 0x002dc6, 0x002dc8, 0x002dce, 0x002dd0, 0x002dd6, 0x002dd8, 0x002dde, 0x00ab01, 0x00ab06, 0x00ab09, 0x00ab0e, 0x00ab11, 0x00ab16, 0x00ab20, 0x00ab26, 0x00ab28, 0x00ab2e)); + SET_ENCODINGS.put("scx=Ethi", + CodePointSet.createNoDedup(0x001200, 0x001248, 0x00124a, 0x00124d, 0x001250, 0x001256, 0x001258, 0x001258, 0x00125a, 0x00125d, 0x001260, 0x001288, 0x00128a, 0x00128d, 0x001290, + 0x0012b0, 0x0012b2, 0x0012b5, 0x0012b8, 0x0012be, 0x0012c0, 0x0012c0, 0x0012c2, 0x0012c5, 0x0012c8, 0x0012d6, 0x0012d8, 0x001310, 0x001312, 0x001315, 0x001318, + 0x00135a, 0x00135d, 0x00137c, 0x001380, 0x001399, 0x002d80, 0x002d96, 0x002da0, 0x002da6, 0x002da8, 0x002dae, 0x002db0, 0x002db6, 0x002db8, 0x002dbe, 0x002dc0, + 0x002dc6, 0x002dc8, 0x002dce, 0x002dd0, 0x002dd6, 0x002dd8, 0x002dde, 0x00ab01, 0x00ab06, 0x00ab09, 0x00ab0e, 0x00ab11, 0x00ab16, 0x00ab20, 0x00ab26, 0x00ab28, + 0x00ab2e, 0x01e7e0, 0x01e7e6, 0x01e7e8, 0x01e7eb, 0x01e7ed, 0x01e7ee, 0x01e7f0, 0x01e7fe)); } private static void populateSCX_GEOR() { @@ -4069,8 +4168,8 @@ private static void populateSCX_GEOR() { } private static void populateSCX_GLAG() { - SET_ENCODINGS.put("scx=Glag", CodePointSet.createNoDedup(0x000484, 0x000484, 0x000487, 0x000487, 0x002c00, 0x002c2e, 0x002c30, 0x002c5e, 0x002e43, 0x002e43, 0x00a66f, 0x00a66f, 0x01e000, - 0x01e006, 0x01e008, 0x01e018, 0x01e01b, 0x01e021, 0x01e023, 0x01e024, 0x01e026, 0x01e02a)); + SET_ENCODINGS.put("scx=Glag", CodePointSet.createNoDedup(0x000484, 0x000484, 0x000487, 0x000487, 0x002c00, 0x002c5f, 0x002e43, 0x002e43, 0x00a66f, 0x00a66f, 0x01e000, 0x01e006, 0x01e008, + 0x01e018, 0x01e01b, 0x01e021, 0x01e023, 0x01e024, 0x01e026, 0x01e02a)); } private static void populateSCX_GONG() { @@ -4129,9 +4228,9 @@ private static void populateSCX_HANI() { SET_ENCODINGS.put("scx=Hani", CodePointSet.createNoDedup(0x002e80, 0x002e99, 0x002e9b, 0x002ef3, 0x002f00, 0x002fd5, 0x003001, 0x003003, 0x003005, 0x003011, 0x003013, 0x00301f, 0x003021, 0x00302d, 0x003030, 0x003030, 0x003037, 0x00303f, 0x0030fb, 0x0030fb, 0x003190, 0x00319f, 0x0031c0, 0x0031e3, 0x003220, 0x003247, 0x003280, 0x0032b0, 0x0032c0, 0x0032cb, 0x0032ff, - 0x0032ff, 0x003358, 0x003370, 0x00337b, 0x00337f, 0x0033e0, 0x0033fe, 0x003400, 0x004dbf, 0x004e00, 0x009ffc, 0x00a700, 0x00a707, 0x00f900, 0x00fa6d, 0x00fa70, - 0x00fad9, 0x00fe45, 0x00fe46, 0x00ff61, 0x00ff65, 0x016ff0, 0x016ff1, 0x01d360, 0x01d371, 0x01f250, 0x01f251, 0x020000, 0x02a6dd, 0x02a700, 0x02b734, 0x02b740, - 0x02b81d, 0x02b820, 0x02cea1, 0x02ceb0, 0x02ebe0, 0x02f800, 0x02fa1d, 0x030000, 0x03134a)); + 0x0032ff, 0x003358, 0x003370, 0x00337b, 0x00337f, 0x0033e0, 0x0033fe, 0x003400, 0x004dbf, 0x004e00, 0x009fff, 0x00a700, 0x00a707, 0x00f900, 0x00fa6d, 0x00fa70, + 0x00fad9, 0x00fe45, 0x00fe46, 0x00ff61, 0x00ff65, 0x016fe2, 0x016fe3, 0x016ff0, 0x016ff1, 0x01d360, 0x01d371, 0x01f250, 0x01f251, 0x020000, 0x02a6df, 0x02a700, + 0x02b738, 0x02b740, 0x02b81d, 0x02b820, 0x02cea1, 0x02ceb0, 0x02ebe0, 0x02f800, 0x02fa1d, 0x030000, 0x03134a)); } private static void populateSCX_HANO() { @@ -4150,7 +4249,7 @@ private static void populateSCX_HEBR() { private static void populateSCX_HIRA() { SET_ENCODINGS.put("scx=Hira", CodePointSet.createNoDedup(0x003001, 0x003003, 0x003008, 0x003011, 0x003013, 0x00301f, 0x003030, 0x003035, 0x003037, 0x003037, 0x00303c, 0x00303d, 0x003041, 0x003096, 0x003099, - 0x0030a0, 0x0030fb, 0x0030fc, 0x00fe45, 0x00fe46, 0x00ff61, 0x00ff65, 0x00ff70, 0x00ff70, 0x00ff9e, 0x00ff9f, 0x01b001, 0x01b11e, 0x01b150, 0x01b152, 0x01f200, + 0x0030a0, 0x0030fb, 0x0030fc, 0x00fe45, 0x00fe46, 0x00ff61, 0x00ff65, 0x00ff70, 0x00ff70, 0x00ff9e, 0x00ff9f, 0x01b001, 0x01b11f, 0x01b150, 0x01b152, 0x01f200, 0x01f200)); } @@ -4183,8 +4282,10 @@ private static void populateSCX_KALI() { } private static void populateSCX_KANA() { - SET_ENCODINGS.put("scx=Kana", CodePointSet.createNoDedup(0x003001, 0x003003, 0x003008, 0x003011, 0x003013, 0x00301f, 0x003030, 0x003035, 0x003037, 0x003037, 0x00303c, 0x00303d, 0x003099, - 0x00309c, 0x0030a0, 0x0030ff, 0x0031f0, 0x0031ff, 0x0032d0, 0x0032fe, 0x003300, 0x003357, 0x00fe45, 0x00fe46, 0x00ff61, 0x00ff9f, 0x01b000, 0x01b000, 0x01b164, 0x01b167)); + SET_ENCODINGS.put("scx=Kana", + CodePointSet.createNoDedup(0x003001, 0x003003, 0x003008, 0x003011, 0x003013, 0x00301f, 0x003030, 0x003035, 0x003037, 0x003037, 0x00303c, 0x00303d, 0x003099, 0x00309c, 0x0030a0, + 0x0030ff, 0x0031f0, 0x0031ff, 0x0032d0, 0x0032fe, 0x003300, 0x003357, 0x00fe45, 0x00fe46, 0x00ff61, 0x00ff9f, 0x01aff0, 0x01aff3, 0x01aff5, 0x01affb, 0x01affd, + 0x01affe, 0x01b000, 0x01b000, 0x01b120, 0x01b122, 0x01b164, 0x01b167)); } private static void populateSCX_KHAR() { @@ -4207,12 +4308,12 @@ private static void populateSCX_KITS() { private static void populateSCX_KNDA() { SET_ENCODINGS.put("scx=Knda", CodePointSet.createNoDedup(0x000951, 0x000952, 0x000964, 0x000965, 0x000c80, 0x000c8c, 0x000c8e, 0x000c90, 0x000c92, 0x000ca8, 0x000caa, 0x000cb3, 0x000cb5, 0x000cb9, 0x000cbc, - 0x000cc4, 0x000cc6, 0x000cc8, 0x000cca, 0x000ccd, 0x000cd5, 0x000cd6, 0x000cde, 0x000cde, 0x000ce0, 0x000ce3, 0x000ce6, 0x000cef, 0x000cf1, 0x000cf2, 0x001cd0, + 0x000cc4, 0x000cc6, 0x000cc8, 0x000cca, 0x000ccd, 0x000cd5, 0x000cd6, 0x000cdd, 0x000cde, 0x000ce0, 0x000ce3, 0x000ce6, 0x000cef, 0x000cf1, 0x000cf2, 0x001cd0, 0x001cd0, 0x001cd2, 0x001cd2, 0x001cda, 0x001cda, 0x001cf2, 0x001cf2, 0x001cf4, 0x001cf4, 0x00a830, 0x00a835)); } private static void populateSCX_KTHI() { - SET_ENCODINGS.put("scx=Kthi", CodePointSet.createNoDedup(0x000966, 0x00096f, 0x00a830, 0x00a839, 0x011080, 0x0110c1, 0x0110cd, 0x0110cd)); + SET_ENCODINGS.put("scx=Kthi", CodePointSet.createNoDedup(0x000966, 0x00096f, 0x00a830, 0x00a839, 0x011080, 0x0110c2, 0x0110cd, 0x0110cd)); } private static void populateSCX_LANA() { @@ -4225,11 +4326,13 @@ private static void populateSCX_LAOO() { } private static void populateSCX_LATN() { - SET_ENCODINGS.put("scx=Latn", CodePointSet.createNoDedup(0x000041, 0x00005a, 0x000061, 0x00007a, 0x0000aa, 0x0000aa, 0x0000ba, 0x0000ba, 0x0000c0, 0x0000d6, 0x0000d8, 0x0000f6, 0x0000f8, - 0x0002b8, 0x0002e0, 0x0002e4, 0x000363, 0x00036f, 0x000485, 0x000486, 0x000951, 0x000952, 0x0010fb, 0x0010fb, 0x001d00, 0x001d25, 0x001d2c, 0x001d5c, 0x001d62, 0x001d65, - 0x001d6b, 0x001d77, 0x001d79, 0x001dbe, 0x001e00, 0x001eff, 0x00202f, 0x00202f, 0x002071, 0x002071, 0x00207f, 0x00207f, 0x002090, 0x00209c, 0x0020f0, 0x0020f0, 0x00212a, - 0x00212b, 0x002132, 0x002132, 0x00214e, 0x00214e, 0x002160, 0x002188, 0x002c60, 0x002c7f, 0x00a700, 0x00a707, 0x00a722, 0x00a787, 0x00a78b, 0x00a7bf, 0x00a7c2, 0x00a7ca, - 0x00a7f5, 0x00a7ff, 0x00a92e, 0x00a92e, 0x00ab30, 0x00ab5a, 0x00ab5c, 0x00ab64, 0x00ab66, 0x00ab69, 0x00fb00, 0x00fb06, 0x00ff21, 0x00ff3a, 0x00ff41, 0x00ff5a)); + SET_ENCODINGS.put("scx=Latn", + CodePointSet.createNoDedup(0x000041, 0x00005a, 0x000061, 0x00007a, 0x0000aa, 0x0000aa, 0x0000ba, 0x0000ba, 0x0000c0, 0x0000d6, 0x0000d8, 0x0000f6, 0x0000f8, 0x0002b8, 0x0002e0, + 0x0002e4, 0x000363, 0x00036f, 0x000485, 0x000486, 0x000951, 0x000952, 0x0010fb, 0x0010fb, 0x001d00, 0x001d25, 0x001d2c, 0x001d5c, 0x001d62, 0x001d65, 0x001d6b, + 0x001d77, 0x001d79, 0x001dbe, 0x001e00, 0x001eff, 0x00202f, 0x00202f, 0x002071, 0x002071, 0x00207f, 0x00207f, 0x002090, 0x00209c, 0x0020f0, 0x0020f0, 0x00212a, + 0x00212b, 0x002132, 0x002132, 0x00214e, 0x00214e, 0x002160, 0x002188, 0x002c60, 0x002c7f, 0x00a700, 0x00a707, 0x00a722, 0x00a787, 0x00a78b, 0x00a7ca, 0x00a7d0, + 0x00a7d1, 0x00a7d3, 0x00a7d3, 0x00a7d5, 0x00a7d9, 0x00a7f2, 0x00a7ff, 0x00a92e, 0x00a92e, 0x00ab30, 0x00ab5a, 0x00ab5c, 0x00ab64, 0x00ab66, 0x00ab69, 0x00fb00, + 0x00fb06, 0x00ff21, 0x00ff3a, 0x00ff41, 0x00ff5a, 0x010780, 0x010785, 0x010787, 0x0107b0, 0x0107b2, 0x0107ba, 0x01df00, 0x01df1e)); } private static void populateSCX_LEPC() { @@ -4307,7 +4410,7 @@ private static void populateSCX_MODI() { } private static void populateSCX_MONG() { - SET_ENCODINGS.put("scx=Mong", CodePointSet.createNoDedup(0x001800, 0x00180e, 0x001810, 0x001819, 0x001820, 0x001878, 0x001880, 0x0018aa, 0x00202f, 0x00202f, 0x011660, 0x01166c)); + SET_ENCODINGS.put("scx=Mong", CodePointSet.createNoDedup(0x001800, 0x001819, 0x001820, 0x001878, 0x001880, 0x0018aa, 0x00202f, 0x00202f, 0x011660, 0x01166c)); } private static void populateSCX_MROO() { @@ -4344,7 +4447,7 @@ private static void populateSCX_NEWA() { } private static void populateSCX_NKOO() { - SET_ENCODINGS.put("scx=Nkoo", CodePointSet.createNoDedup(0x0007c0, 0x0007fa, 0x0007fd, 0x0007ff)); + SET_ENCODINGS.put("scx=Nkoo", CodePointSet.createNoDedup(0x00060c, 0x00060c, 0x00061b, 0x00061b, 0x00061f, 0x00061f, 0x0007c0, 0x0007fa, 0x0007fd, 0x0007ff, 0x00fd3e, 0x00fd3f)); } private static void populateSCX_NSHU() { @@ -4378,6 +4481,10 @@ private static void populateSCX_OSMA() { SET_ENCODINGS.put("scx=Osma", CodePointSet.createNoDedup(0x010480, 0x01049d, 0x0104a0, 0x0104a9)); } + private static void populateSCX_OUGR() { + SET_ENCODINGS.put("scx=Ougr", CodePointSet.createNoDedup(0x000640, 0x000640, 0x010af2, 0x010af2, 0x010f70, 0x010f89)); + } + private static void populateSCX_PALM() { SET_ENCODINGS.put("scx=Palm", CodePointSet.createNoDedup(0x010860, 0x01087f)); } @@ -4490,7 +4597,7 @@ private static void populateSCX_SYLO() { private static void populateSCX_SYRC() { SET_ENCODINGS.put("scx=Syrc", CodePointSet.createNoDedup(0x00060c, 0x00060c, 0x00061b, 0x00061c, 0x00061f, 0x00061f, 0x000640, 0x000640, 0x00064b, 0x000655, 0x000670, 0x000670, 0x000700, - 0x00070d, 0x00070f, 0x00074a, 0x00074d, 0x00074f, 0x000860, 0x00086a, 0x001df8, 0x001df8)); + 0x00070d, 0x00070f, 0x00074a, 0x00074d, 0x00074f, 0x000860, 0x00086a, 0x001df8, 0x001df8, 0x001dfa, 0x001dfa)); } private static void populateSCX_TAGB() { @@ -4498,7 +4605,7 @@ private static void populateSCX_TAGB() { } private static void populateSCX_TAKR() { - SET_ENCODINGS.put("scx=Takr", CodePointSet.createNoDedup(0x000964, 0x000965, 0x00a830, 0x00a839, 0x011680, 0x0116b8, 0x0116c0, 0x0116c9)); + SET_ENCODINGS.put("scx=Takr", CodePointSet.createNoDedup(0x000964, 0x000965, 0x00a830, 0x00a839, 0x011680, 0x0116b9, 0x0116c0, 0x0116c9)); } private static void populateSCX_TALE() { @@ -4527,9 +4634,9 @@ private static void populateSCX_TAVT() { private static void populateSCX_TELU() { SET_ENCODINGS.put("scx=Telu", - CodePointSet.createNoDedup(0x000951, 0x000952, 0x000964, 0x000965, 0x000c00, 0x000c0c, 0x000c0e, 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3d, 0x000c44, 0x000c46, - 0x000c48, 0x000c4a, 0x000c4d, 0x000c55, 0x000c56, 0x000c58, 0x000c5a, 0x000c60, 0x000c63, 0x000c66, 0x000c6f, 0x000c77, 0x000c7f, 0x001cda, 0x001cda, 0x001cf2, - 0x001cf2)); + CodePointSet.createNoDedup(0x000951, 0x000952, 0x000964, 0x000965, 0x000c00, 0x000c0c, 0x000c0e, 0x000c10, 0x000c12, 0x000c28, 0x000c2a, 0x000c39, 0x000c3c, 0x000c44, 0x000c46, + 0x000c48, 0x000c4a, 0x000c4d, 0x000c55, 0x000c56, 0x000c58, 0x000c5a, 0x000c5d, 0x000c5d, 0x000c60, 0x000c63, 0x000c66, 0x000c6f, 0x000c77, 0x000c7f, 0x001cda, + 0x001cda, 0x001cf2, 0x001cf2)); } private static void populateSCX_TFNG() { @@ -4537,7 +4644,7 @@ private static void populateSCX_TFNG() { } private static void populateSCX_TGLG() { - SET_ENCODINGS.put("scx=Tglg", CodePointSet.createNoDedup(0x001700, 0x00170c, 0x00170e, 0x001714, 0x001735, 0x001736)); + SET_ENCODINGS.put("scx=Tglg", CodePointSet.createNoDedup(0x001700, 0x001715, 0x00171f, 0x00171f, 0x001735, 0x001736)); } private static void populateSCX_THAA() { @@ -4558,6 +4665,14 @@ private static void populateSCX_TIRH() { SET_ENCODINGS.put("scx=Tirh", CodePointSet.createNoDedup(0x000951, 0x000952, 0x000964, 0x000965, 0x001cf2, 0x001cf2, 0x00a830, 0x00a839, 0x011480, 0x0114c7, 0x0114d0, 0x0114d9)); } + private static void populateSCX_TNSA() { + SET_ENCODINGS.put("scx=Tnsa", CodePointSet.createNoDedup(0x016a70, 0x016abe, 0x016ac0, 0x016ac9)); + } + + private static void populateSCX_TOTO() { + SET_ENCODINGS.put("scx=Toto", CodePointSet.createNoDedup(0x01e290, 0x01e2ae)); + } + private static void populateSCX_UGAR() { SET_ENCODINGS.put("scx=Ugar", CodePointSet.createNoDedup(0x010380, 0x01039d, 0x01039f, 0x01039f)); } @@ -4566,6 +4681,11 @@ private static void populateSCX_VAII() { SET_ENCODINGS.put("scx=Vaii", CodePointSet.createNoDedup(0x00a500, 0x00a62b)); } + private static void populateSCX_VITH() { + SET_ENCODINGS.put("scx=Vith", CodePointSet.createNoDedup(0x010570, 0x01057a, 0x01057c, 0x01058a, 0x01058c, 0x010592, 0x010594, 0x010595, 0x010597, 0x0105a1, 0x0105a3, 0x0105b1, 0x0105b3, + 0x0105b9, 0x0105bb, 0x0105bc)); + } + private static void populateSCX_WARA() { SET_ENCODINGS.put("scx=Wara", CodePointSet.createNoDedup(0x0118a0, 0x0118f2, 0x0118ff, 0x0118ff)); } @@ -4598,48 +4718,48 @@ private static void populateSCX_ZANB() { private static void populateSCX_ZINH() { SET_ENCODINGS.put("scx=Zinh", - CodePointSet.createNoDedup(0x000300, 0x000341, 0x000343, 0x000344, 0x000346, 0x000362, 0x000953, 0x000954, 0x001ab0, 0x001ac0, 0x001dc2, 0x001df7, 0x001df9, 0x001df9, 0x001dfb, - 0x001dff, 0x00200c, 0x00200d, 0x0020d0, 0x0020ef, 0x00fe00, 0x00fe0f, 0x00fe20, 0x00fe2d, 0x0101fd, 0x0101fd, 0x01d167, 0x01d169, 0x01d17b, 0x01d182, 0x01d185, - 0x01d18b, 0x01d1aa, 0x01d1ad, 0x0e0100, 0x0e01ef)); + CodePointSet.createNoDedup(0x000300, 0x000341, 0x000343, 0x000344, 0x000346, 0x000362, 0x000953, 0x000954, 0x001ab0, 0x001ace, 0x001dc2, 0x001df7, 0x001df9, 0x001df9, 0x001dfb, + 0x001dff, 0x00200c, 0x00200d, 0x0020d0, 0x0020ef, 0x00fe00, 0x00fe0f, 0x00fe20, 0x00fe2d, 0x0101fd, 0x0101fd, 0x01cf00, 0x01cf2d, 0x01cf30, 0x01cf46, 0x01d167, + 0x01d169, 0x01d17b, 0x01d182, 0x01d185, 0x01d18b, 0x01d1aa, 0x01d1ad, 0x0e0100, 0x0e01ef)); } private static void populateSCX_ZYYY() { SET_ENCODINGS.put("scx=Zyyy", CodePointSet.createNoDedup(0x000000, 0x000040, 0x00005b, 0x000060, 0x00007b, 0x0000a9, 0x0000ab, 0x0000b9, 0x0000bb, 0x0000bf, 0x0000d7, 0x0000d7, 0x0000f7, 0x0000f7, 0x0002b9, 0x0002df, 0x0002e5, 0x0002e9, 0x0002ec, 0x0002ff, 0x000374, 0x000374, 0x00037e, 0x00037e, 0x000385, 0x000385, 0x000387, 0x000387, 0x000605, 0x000605, 0x0006dd, 0x0006dd, 0x0008e2, 0x0008e2, 0x000e3f, 0x000e3f, 0x000fd5, 0x000fd8, 0x0016eb, 0x0016ed, 0x002000, 0x00200b, 0x00200e, 0x00202e, 0x002030, 0x002064, 0x002066, - 0x002070, 0x002074, 0x00207e, 0x002080, 0x00208e, 0x0020a0, 0x0020bf, 0x002100, 0x002125, 0x002127, 0x002129, 0x00212c, 0x002131, 0x002133, 0x00214d, 0x00214f, 0x00215f, + 0x002070, 0x002074, 0x00207e, 0x002080, 0x00208e, 0x0020a0, 0x0020c0, 0x002100, 0x002125, 0x002127, 0x002129, 0x00212c, 0x002131, 0x002133, 0x00214d, 0x00214f, 0x00215f, 0x002189, 0x00218b, 0x002190, 0x002426, 0x002440, 0x00244a, 0x002460, 0x0027ff, 0x002900, 0x002b73, 0x002b76, 0x002b95, 0x002b97, 0x002bff, 0x002e00, 0x002e42, 0x002e44, - 0x002e52, 0x002ff0, 0x002ffb, 0x003000, 0x003000, 0x003004, 0x003004, 0x003012, 0x003012, 0x003020, 0x003020, 0x003036, 0x003036, 0x003248, 0x00325f, 0x00327f, 0x00327f, + 0x002e5d, 0x002ff0, 0x002ffb, 0x003000, 0x003000, 0x003004, 0x003004, 0x003012, 0x003012, 0x003020, 0x003020, 0x003036, 0x003036, 0x003248, 0x00325f, 0x00327f, 0x00327f, 0x0032b1, 0x0032bf, 0x0032cc, 0x0032cf, 0x003371, 0x00337a, 0x003380, 0x0033df, 0x0033ff, 0x0033ff, 0x004dc0, 0x004dff, 0x00a708, 0x00a721, 0x00a788, 0x00a78a, 0x00ab5b, - 0x00ab5b, 0x00ab6a, 0x00ab6b, 0x00fd3e, 0x00fd3f, 0x00fe10, 0x00fe19, 0x00fe30, 0x00fe44, 0x00fe47, 0x00fe52, 0x00fe54, 0x00fe66, 0x00fe68, 0x00fe6b, 0x00feff, 0x00feff, - 0x00ff01, 0x00ff20, 0x00ff3b, 0x00ff40, 0x00ff5b, 0x00ff60, 0x00ffe0, 0x00ffe6, 0x00ffe8, 0x00ffee, 0x00fff9, 0x00fffd, 0x010190, 0x01019c, 0x0101d0, 0x0101fc, 0x016fe2, - 0x016fe3, 0x01d000, 0x01d0f5, 0x01d100, 0x01d126, 0x01d129, 0x01d166, 0x01d16a, 0x01d17a, 0x01d183, 0x01d184, 0x01d18c, 0x01d1a9, 0x01d1ae, 0x01d1e8, 0x01d2e0, 0x01d2f3, - 0x01d300, 0x01d356, 0x01d372, 0x01d378, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, - 0x01d4b9, 0x01d4bb, 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, - 0x01d540, 0x01d544, 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d7cb, 0x01d7ce, 0x01d7ff, 0x01ec71, 0x01ecb4, 0x01ed01, 0x01ed3d, 0x01f000, - 0x01f02b, 0x01f030, 0x01f093, 0x01f0a0, 0x01f0ae, 0x01f0b1, 0x01f0bf, 0x01f0c1, 0x01f0cf, 0x01f0d1, 0x01f0f5, 0x01f100, 0x01f1ad, 0x01f1e6, 0x01f1ff, 0x01f201, 0x01f202, - 0x01f210, 0x01f23b, 0x01f240, 0x01f248, 0x01f260, 0x01f265, 0x01f300, 0x01f6d7, 0x01f6e0, 0x01f6ec, 0x01f6f0, 0x01f6fc, 0x01f700, 0x01f773, 0x01f780, 0x01f7d8, 0x01f7e0, - 0x01f7eb, 0x01f800, 0x01f80b, 0x01f810, 0x01f847, 0x01f850, 0x01f859, 0x01f860, 0x01f887, 0x01f890, 0x01f8ad, 0x01f8b0, 0x01f8b1, 0x01f900, 0x01f978, 0x01f97a, 0x01f9cb, - 0x01f9cd, 0x01fa53, 0x01fa60, 0x01fa6d, 0x01fa70, 0x01fa74, 0x01fa78, 0x01fa7a, 0x01fa80, 0x01fa86, 0x01fa90, 0x01faa8, 0x01fab0, 0x01fab6, 0x01fac0, 0x01fac2, 0x01fad0, - 0x01fad6, 0x01fb00, 0x01fb92, 0x01fb94, 0x01fbca, 0x01fbf0, 0x01fbf9, 0x0e0001, 0x0e0001, 0x0e0020, 0x0e007f)); + 0x00ab5b, 0x00ab6a, 0x00ab6b, 0x00fe10, 0x00fe19, 0x00fe30, 0x00fe44, 0x00fe47, 0x00fe52, 0x00fe54, 0x00fe66, 0x00fe68, 0x00fe6b, 0x00feff, 0x00feff, 0x00ff01, 0x00ff20, + 0x00ff3b, 0x00ff40, 0x00ff5b, 0x00ff60, 0x00ffe0, 0x00ffe6, 0x00ffe8, 0x00ffee, 0x00fff9, 0x00fffd, 0x010190, 0x01019c, 0x0101d0, 0x0101fc, 0x01cf50, 0x01cfc3, 0x01d000, + 0x01d0f5, 0x01d100, 0x01d126, 0x01d129, 0x01d166, 0x01d16a, 0x01d17a, 0x01d183, 0x01d184, 0x01d18c, 0x01d1a9, 0x01d1ae, 0x01d1ea, 0x01d2e0, 0x01d2f3, 0x01d300, 0x01d356, + 0x01d372, 0x01d378, 0x01d400, 0x01d454, 0x01d456, 0x01d49c, 0x01d49e, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, 0x01d4a9, 0x01d4ac, 0x01d4ae, 0x01d4b9, 0x01d4bb, + 0x01d4bb, 0x01d4bd, 0x01d4c3, 0x01d4c5, 0x01d505, 0x01d507, 0x01d50a, 0x01d50d, 0x01d514, 0x01d516, 0x01d51c, 0x01d51e, 0x01d539, 0x01d53b, 0x01d53e, 0x01d540, 0x01d544, + 0x01d546, 0x01d546, 0x01d54a, 0x01d550, 0x01d552, 0x01d6a5, 0x01d6a8, 0x01d7cb, 0x01d7ce, 0x01d7ff, 0x01ec71, 0x01ecb4, 0x01ed01, 0x01ed3d, 0x01f000, 0x01f02b, 0x01f030, + 0x01f093, 0x01f0a0, 0x01f0ae, 0x01f0b1, 0x01f0bf, 0x01f0c1, 0x01f0cf, 0x01f0d1, 0x01f0f5, 0x01f100, 0x01f1ad, 0x01f1e6, 0x01f1ff, 0x01f201, 0x01f202, 0x01f210, 0x01f23b, + 0x01f240, 0x01f248, 0x01f260, 0x01f265, 0x01f300, 0x01f6d7, 0x01f6dd, 0x01f6ec, 0x01f6f0, 0x01f6fc, 0x01f700, 0x01f773, 0x01f780, 0x01f7d8, 0x01f7e0, 0x01f7eb, 0x01f7f0, + 0x01f7f0, 0x01f800, 0x01f80b, 0x01f810, 0x01f847, 0x01f850, 0x01f859, 0x01f860, 0x01f887, 0x01f890, 0x01f8ad, 0x01f8b0, 0x01f8b1, 0x01f900, 0x01fa53, 0x01fa60, 0x01fa6d, + 0x01fa70, 0x01fa74, 0x01fa78, 0x01fa7c, 0x01fa80, 0x01fa86, 0x01fa90, 0x01faac, 0x01fab0, 0x01faba, 0x01fac0, 0x01fac5, 0x01fad0, 0x01fad9, 0x01fae0, 0x01fae7, 0x01faf0, + 0x01faf6, 0x01fb00, 0x01fb92, 0x01fb94, 0x01fbca, 0x01fbf0, 0x01fbf9, 0x0e0001, 0x0e0001, 0x0e0020, 0x0e007f)); } private static void populateSCX_ZZZZ() { SET_ENCODINGS.put("scx=Zzzz", CodePointSet.createNoDedup(0x000378, 0x000379, 0x000380, 0x000383, 0x00038b, 0x00038b, 0x00038d, 0x00038d, 0x0003a2, 0x0003a2, 0x000530, 0x000530, 0x000557, - 0x000558, 0x00058b, 0x00058c, 0x000590, 0x000590, 0x0005c8, 0x0005cf, 0x0005eb, 0x0005ee, 0x0005f5, 0x0005ff, 0x00061d, 0x00061d, 0x00070e, 0x00070e, 0x00074b, 0x00074c, - 0x0007b2, 0x0007bf, 0x0007fb, 0x0007fc, 0x00082e, 0x00082f, 0x00083f, 0x00083f, 0x00085c, 0x00085d, 0x00085f, 0x00085f, 0x00086b, 0x00089f, 0x0008b5, 0x0008b5, 0x0008c8, - 0x0008d2, 0x000984, 0x000984, 0x00098d, 0x00098e, 0x000991, 0x000992, 0x0009a9, 0x0009a9, 0x0009b1, 0x0009b1, 0x0009b3, 0x0009b5, 0x0009ba, 0x0009bb, 0x0009c5, 0x0009c6, - 0x0009c9, 0x0009ca, 0x0009cf, 0x0009d6, 0x0009d8, 0x0009db, 0x0009de, 0x0009de, 0x0009e4, 0x0009e5, 0x0009ff, 0x000a00, 0x000a04, 0x000a04, 0x000a0b, 0x000a0e, 0x000a11, - 0x000a12, 0x000a29, 0x000a29, 0x000a31, 0x000a31, 0x000a34, 0x000a34, 0x000a37, 0x000a37, 0x000a3a, 0x000a3b, 0x000a3d, 0x000a3d, 0x000a43, 0x000a46, 0x000a49, 0x000a4a, - 0x000a4e, 0x000a50, 0x000a52, 0x000a58, 0x000a5d, 0x000a5d, 0x000a5f, 0x000a65, 0x000a77, 0x000a80, 0x000a84, 0x000a84, 0x000a8e, 0x000a8e, 0x000a92, 0x000a92, 0x000aa9, - 0x000aa9, 0x000ab1, 0x000ab1, 0x000ab4, 0x000ab4, 0x000aba, 0x000abb, 0x000ac6, 0x000ac6, 0x000aca, 0x000aca, 0x000ace, 0x000acf, 0x000ad1, 0x000adf, 0x000ae4, 0x000ae5, - 0x000af2, 0x000af8, 0x000b00, 0x000b00, 0x000b04, 0x000b04, 0x000b0d, 0x000b0e, 0x000b11, 0x000b12, 0x000b29, 0x000b29, 0x000b31, 0x000b31, 0x000b34, 0x000b34, 0x000b3a, - 0x000b3b, 0x000b45, 0x000b46, 0x000b49, 0x000b4a, 0x000b4e, 0x000b54, 0x000b58, 0x000b5b, 0x000b5e, 0x000b5e, 0x000b64, 0x000b65, 0x000b78, 0x000b81, 0x000b84, 0x000b84, - 0x000b8b, 0x000b8d, 0x000b91, 0x000b91, 0x000b96, 0x000b98, 0x000b9b, 0x000b9b, 0x000b9d, 0x000b9d, 0x000ba0, 0x000ba2, 0x000ba5, 0x000ba7, 0x000bab, 0x000bad, 0x000bba, - 0x000bbd, 0x000bc3, 0x000bc5, 0x000bc9, 0x000bc9, 0x000bce, 0x000bcf, 0x000bd1, 0x000bd6, 0x000bd8, 0x000be5, 0x000bfb, 0x000bff, 0x000c0d, 0x000c0d, 0x000c11, 0x000c11, - 0x000c29, 0x000c29, 0x000c3a, 0x000c3c, 0x000c45, 0x000c45, 0x000c49, 0x000c49, 0x000c4e, 0x000c54, 0x000c57, 0x000c57, 0x000c5b, 0x000c5f, 0x000c64, 0x000c65, 0x000c70, + 0x000558, 0x00058b, 0x00058c, 0x000590, 0x000590, 0x0005c8, 0x0005cf, 0x0005eb, 0x0005ee, 0x0005f5, 0x0005ff, 0x00070e, 0x00070e, 0x00074b, 0x00074c, 0x0007b2, 0x0007bf, + 0x0007fb, 0x0007fc, 0x00082e, 0x00082f, 0x00083f, 0x00083f, 0x00085c, 0x00085d, 0x00085f, 0x00085f, 0x00086b, 0x00086f, 0x00088f, 0x00088f, 0x000892, 0x000897, 0x000984, + 0x000984, 0x00098d, 0x00098e, 0x000991, 0x000992, 0x0009a9, 0x0009a9, 0x0009b1, 0x0009b1, 0x0009b3, 0x0009b5, 0x0009ba, 0x0009bb, 0x0009c5, 0x0009c6, 0x0009c9, 0x0009ca, + 0x0009cf, 0x0009d6, 0x0009d8, 0x0009db, 0x0009de, 0x0009de, 0x0009e4, 0x0009e5, 0x0009ff, 0x000a00, 0x000a04, 0x000a04, 0x000a0b, 0x000a0e, 0x000a11, 0x000a12, 0x000a29, + 0x000a29, 0x000a31, 0x000a31, 0x000a34, 0x000a34, 0x000a37, 0x000a37, 0x000a3a, 0x000a3b, 0x000a3d, 0x000a3d, 0x000a43, 0x000a46, 0x000a49, 0x000a4a, 0x000a4e, 0x000a50, + 0x000a52, 0x000a58, 0x000a5d, 0x000a5d, 0x000a5f, 0x000a65, 0x000a77, 0x000a80, 0x000a84, 0x000a84, 0x000a8e, 0x000a8e, 0x000a92, 0x000a92, 0x000aa9, 0x000aa9, 0x000ab1, + 0x000ab1, 0x000ab4, 0x000ab4, 0x000aba, 0x000abb, 0x000ac6, 0x000ac6, 0x000aca, 0x000aca, 0x000ace, 0x000acf, 0x000ad1, 0x000adf, 0x000ae4, 0x000ae5, 0x000af2, 0x000af8, + 0x000b00, 0x000b00, 0x000b04, 0x000b04, 0x000b0d, 0x000b0e, 0x000b11, 0x000b12, 0x000b29, 0x000b29, 0x000b31, 0x000b31, 0x000b34, 0x000b34, 0x000b3a, 0x000b3b, 0x000b45, + 0x000b46, 0x000b49, 0x000b4a, 0x000b4e, 0x000b54, 0x000b58, 0x000b5b, 0x000b5e, 0x000b5e, 0x000b64, 0x000b65, 0x000b78, 0x000b81, 0x000b84, 0x000b84, 0x000b8b, 0x000b8d, + 0x000b91, 0x000b91, 0x000b96, 0x000b98, 0x000b9b, 0x000b9b, 0x000b9d, 0x000b9d, 0x000ba0, 0x000ba2, 0x000ba5, 0x000ba7, 0x000bab, 0x000bad, 0x000bba, 0x000bbd, 0x000bc3, + 0x000bc5, 0x000bc9, 0x000bc9, 0x000bce, 0x000bcf, 0x000bd1, 0x000bd6, 0x000bd8, 0x000be5, 0x000bfb, 0x000bff, 0x000c0d, 0x000c0d, 0x000c11, 0x000c11, 0x000c29, 0x000c29, + 0x000c3a, 0x000c3b, 0x000c45, 0x000c45, 0x000c49, 0x000c49, 0x000c4e, 0x000c54, 0x000c57, 0x000c57, 0x000c5b, 0x000c5c, 0x000c5e, 0x000c5f, 0x000c64, 0x000c65, 0x000c70, 0x000c76, 0x000c8d, 0x000c8d, 0x000c91, 0x000c91, 0x000ca9, 0x000ca9, 0x000cb4, 0x000cb4, 0x000cba, 0x000cbb, 0x000cc5, 0x000cc5, 0x000cc9, 0x000cc9, 0x000cce, 0x000cd4, - 0x000cd7, 0x000cdd, 0x000cdf, 0x000cdf, 0x000ce4, 0x000ce5, 0x000cf0, 0x000cf0, 0x000cf3, 0x000cff, 0x000d0d, 0x000d0d, 0x000d11, 0x000d11, 0x000d45, 0x000d45, 0x000d49, + 0x000cd7, 0x000cdc, 0x000cdf, 0x000cdf, 0x000ce4, 0x000ce5, 0x000cf0, 0x000cf0, 0x000cf3, 0x000cff, 0x000d0d, 0x000d0d, 0x000d11, 0x000d11, 0x000d45, 0x000d45, 0x000d49, 0x000d49, 0x000d50, 0x000d53, 0x000d64, 0x000d65, 0x000d80, 0x000d80, 0x000d84, 0x000d84, 0x000d97, 0x000d99, 0x000db2, 0x000db2, 0x000dbc, 0x000dbc, 0x000dbe, 0x000dbf, 0x000dc7, 0x000dc9, 0x000dcb, 0x000dce, 0x000dd5, 0x000dd5, 0x000dd7, 0x000dd7, 0x000de0, 0x000de5, 0x000df0, 0x000df1, 0x000df5, 0x000e00, 0x000e3b, 0x000e3e, 0x000e5c, 0x000e80, 0x000e83, 0x000e83, 0x000e85, 0x000e85, 0x000e8b, 0x000e8b, 0x000ea4, 0x000ea4, 0x000ea6, 0x000ea6, 0x000ebe, 0x000ebf, 0x000ec5, 0x000ec5, 0x000ec7, 0x000ec7, @@ -4647,63 +4767,66 @@ private static void populateSCX_ZZZZ() { 0x000fff, 0x0010c6, 0x0010c6, 0x0010c8, 0x0010cc, 0x0010ce, 0x0010cf, 0x001249, 0x001249, 0x00124e, 0x00124f, 0x001257, 0x001257, 0x001259, 0x001259, 0x00125e, 0x00125f, 0x001289, 0x001289, 0x00128e, 0x00128f, 0x0012b1, 0x0012b1, 0x0012b6, 0x0012b7, 0x0012bf, 0x0012bf, 0x0012c1, 0x0012c1, 0x0012c6, 0x0012c7, 0x0012d7, 0x0012d7, 0x001311, 0x001311, 0x001316, 0x001317, 0x00135b, 0x00135c, 0x00137d, 0x00137f, 0x00139a, 0x00139f, 0x0013f6, 0x0013f7, 0x0013fe, 0x0013ff, 0x00169d, 0x00169f, 0x0016f9, 0x0016ff, - 0x00170d, 0x00170d, 0x001715, 0x00171f, 0x001737, 0x00173f, 0x001754, 0x00175f, 0x00176d, 0x00176d, 0x001771, 0x001771, 0x001774, 0x00177f, 0x0017de, 0x0017df, 0x0017ea, - 0x0017ef, 0x0017fa, 0x0017ff, 0x00180f, 0x00180f, 0x00181a, 0x00181f, 0x001879, 0x00187f, 0x0018ab, 0x0018af, 0x0018f6, 0x0018ff, 0x00191f, 0x00191f, 0x00192c, 0x00192f, - 0x00193c, 0x00193f, 0x001941, 0x001943, 0x00196e, 0x00196f, 0x001975, 0x00197f, 0x0019ac, 0x0019af, 0x0019ca, 0x0019cf, 0x0019db, 0x0019dd, 0x001a1c, 0x001a1d, 0x001a5f, - 0x001a5f, 0x001a7d, 0x001a7e, 0x001a8a, 0x001a8f, 0x001a9a, 0x001a9f, 0x001aae, 0x001aaf, 0x001ac1, 0x001aff, 0x001b4c, 0x001b4f, 0x001b7d, 0x001b7f, 0x001bf4, 0x001bfb, - 0x001c38, 0x001c3a, 0x001c4a, 0x001c4c, 0x001c89, 0x001c8f, 0x001cbb, 0x001cbc, 0x001cc8, 0x001ccf, 0x001cfb, 0x001cff, 0x001dfa, 0x001dfa, 0x001f16, 0x001f17, 0x001f1e, - 0x001f1f, 0x001f46, 0x001f47, 0x001f4e, 0x001f4f, 0x001f58, 0x001f58, 0x001f5a, 0x001f5a, 0x001f5c, 0x001f5c, 0x001f5e, 0x001f5e, 0x001f7e, 0x001f7f, 0x001fb5, 0x001fb5, - 0x001fc5, 0x001fc5, 0x001fd4, 0x001fd5, 0x001fdc, 0x001fdc, 0x001ff0, 0x001ff1, 0x001ff5, 0x001ff5, 0x001fff, 0x001fff, 0x002065, 0x002065, 0x002072, 0x002073, 0x00208f, - 0x00208f, 0x00209d, 0x00209f, 0x0020c0, 0x0020cf, 0x0020f1, 0x0020ff, 0x00218c, 0x00218f, 0x002427, 0x00243f, 0x00244b, 0x00245f, 0x002b74, 0x002b75, 0x002b96, 0x002b96, - 0x002c2f, 0x002c2f, 0x002c5f, 0x002c5f, 0x002cf4, 0x002cf8, 0x002d26, 0x002d26, 0x002d28, 0x002d2c, 0x002d2e, 0x002d2f, 0x002d68, 0x002d6e, 0x002d71, 0x002d7e, 0x002d97, - 0x002d9f, 0x002da7, 0x002da7, 0x002daf, 0x002daf, 0x002db7, 0x002db7, 0x002dbf, 0x002dbf, 0x002dc7, 0x002dc7, 0x002dcf, 0x002dcf, 0x002dd7, 0x002dd7, 0x002ddf, 0x002ddf, - 0x002e53, 0x002e7f, 0x002e9a, 0x002e9a, 0x002ef4, 0x002eff, 0x002fd6, 0x002fef, 0x002ffc, 0x002fff, 0x003040, 0x003040, 0x003097, 0x003098, 0x003100, 0x003104, 0x003130, - 0x003130, 0x00318f, 0x00318f, 0x0031e4, 0x0031ef, 0x00321f, 0x00321f, 0x009ffd, 0x009fff, 0x00a48d, 0x00a48f, 0x00a4c7, 0x00a4cf, 0x00a62c, 0x00a63f, 0x00a6f8, 0x00a6ff, - 0x00a7c0, 0x00a7c1, 0x00a7cb, 0x00a7f4, 0x00a82d, 0x00a82f, 0x00a83a, 0x00a83f, 0x00a878, 0x00a87f, 0x00a8c6, 0x00a8cd, 0x00a8da, 0x00a8df, 0x00a954, 0x00a95e, 0x00a97d, - 0x00a97f, 0x00a9ce, 0x00a9ce, 0x00a9da, 0x00a9dd, 0x00a9ff, 0x00a9ff, 0x00aa37, 0x00aa3f, 0x00aa4e, 0x00aa4f, 0x00aa5a, 0x00aa5b, 0x00aac3, 0x00aada, 0x00aaf7, 0x00ab00, - 0x00ab07, 0x00ab08, 0x00ab0f, 0x00ab10, 0x00ab17, 0x00ab1f, 0x00ab27, 0x00ab27, 0x00ab2f, 0x00ab2f, 0x00ab6c, 0x00ab6f, 0x00abee, 0x00abef, 0x00abfa, 0x00abff, 0x00d7a4, - 0x00d7af, 0x00d7c7, 0x00d7ca, 0x00d7fc, 0x00f8ff, 0x00fa6e, 0x00fa6f, 0x00fada, 0x00faff, 0x00fb07, 0x00fb12, 0x00fb18, 0x00fb1c, 0x00fb37, 0x00fb37, 0x00fb3d, 0x00fb3d, - 0x00fb3f, 0x00fb3f, 0x00fb42, 0x00fb42, 0x00fb45, 0x00fb45, 0x00fbc2, 0x00fbd2, 0x00fd40, 0x00fd4f, 0x00fd90, 0x00fd91, 0x00fdc8, 0x00fdef, 0x00fdfe, 0x00fdff, 0x00fe1a, - 0x00fe1f, 0x00fe53, 0x00fe53, 0x00fe67, 0x00fe67, 0x00fe6c, 0x00fe6f, 0x00fe75, 0x00fe75, 0x00fefd, 0x00fefe, 0x00ff00, 0x00ff00, 0x00ffbf, 0x00ffc1, 0x00ffc8, 0x00ffc9, - 0x00ffd0, 0x00ffd1, 0x00ffd8, 0x00ffd9, 0x00ffdd, 0x00ffdf, 0x00ffe7, 0x00ffe7, 0x00ffef, 0x00fff8, 0x00fffe, 0x00ffff, 0x01000c, 0x01000c, 0x010027, 0x010027, 0x01003b, - 0x01003b, 0x01003e, 0x01003e, 0x01004e, 0x01004f, 0x01005e, 0x01007f, 0x0100fb, 0x0100ff, 0x010103, 0x010106, 0x010134, 0x010136, 0x01018f, 0x01018f, 0x01019d, 0x01019f, - 0x0101a1, 0x0101cf, 0x0101fe, 0x01027f, 0x01029d, 0x01029f, 0x0102d1, 0x0102df, 0x0102fc, 0x0102ff, 0x010324, 0x01032c, 0x01034b, 0x01034f, 0x01037b, 0x01037f, 0x01039e, - 0x01039e, 0x0103c4, 0x0103c7, 0x0103d6, 0x0103ff, 0x01049e, 0x01049f, 0x0104aa, 0x0104af, 0x0104d4, 0x0104d7, 0x0104fc, 0x0104ff, 0x010528, 0x01052f, 0x010564, 0x01056e, - 0x010570, 0x0105ff, 0x010737, 0x01073f, 0x010756, 0x01075f, 0x010768, 0x0107ff, 0x010806, 0x010807, 0x010809, 0x010809, 0x010836, 0x010836, 0x010839, 0x01083b, 0x01083d, - 0x01083e, 0x010856, 0x010856, 0x01089f, 0x0108a6, 0x0108b0, 0x0108df, 0x0108f3, 0x0108f3, 0x0108f6, 0x0108fa, 0x01091c, 0x01091e, 0x01093a, 0x01093e, 0x010940, 0x01097f, - 0x0109b8, 0x0109bb, 0x0109d0, 0x0109d1, 0x010a04, 0x010a04, 0x010a07, 0x010a0b, 0x010a14, 0x010a14, 0x010a18, 0x010a18, 0x010a36, 0x010a37, 0x010a3b, 0x010a3e, 0x010a49, - 0x010a4f, 0x010a59, 0x010a5f, 0x010aa0, 0x010abf, 0x010ae7, 0x010aea, 0x010af7, 0x010aff, 0x010b36, 0x010b38, 0x010b56, 0x010b57, 0x010b73, 0x010b77, 0x010b92, 0x010b98, - 0x010b9d, 0x010ba8, 0x010bb0, 0x010bff, 0x010c49, 0x010c7f, 0x010cb3, 0x010cbf, 0x010cf3, 0x010cf9, 0x010d28, 0x010d2f, 0x010d3a, 0x010e5f, 0x010e7f, 0x010e7f, 0x010eaa, - 0x010eaa, 0x010eae, 0x010eaf, 0x010eb2, 0x010eff, 0x010f28, 0x010f2f, 0x010f5a, 0x010faf, 0x010fcc, 0x010fdf, 0x010ff7, 0x010fff, 0x01104e, 0x011051, 0x011070, 0x01107e, - 0x0110c2, 0x0110cc, 0x0110ce, 0x0110cf, 0x0110e9, 0x0110ef, 0x0110fa, 0x0110ff, 0x011135, 0x011135, 0x011148, 0x01114f, 0x011177, 0x01117f, 0x0111e0, 0x0111e0, 0x0111f5, - 0x0111ff, 0x011212, 0x011212, 0x01123f, 0x01127f, 0x011287, 0x011287, 0x011289, 0x011289, 0x01128e, 0x01128e, 0x01129e, 0x01129e, 0x0112aa, 0x0112af, 0x0112eb, 0x0112ef, - 0x0112fa, 0x0112ff, 0x011304, 0x011304, 0x01130d, 0x01130e, 0x011311, 0x011312, 0x011329, 0x011329, 0x011331, 0x011331, 0x011334, 0x011334, 0x01133a, 0x01133a, 0x011345, - 0x011346, 0x011349, 0x01134a, 0x01134e, 0x01134f, 0x011351, 0x011356, 0x011358, 0x01135c, 0x011364, 0x011365, 0x01136d, 0x01136f, 0x011375, 0x0113ff, 0x01145c, 0x01145c, - 0x011462, 0x01147f, 0x0114c8, 0x0114cf, 0x0114da, 0x01157f, 0x0115b6, 0x0115b7, 0x0115de, 0x0115ff, 0x011645, 0x01164f, 0x01165a, 0x01165f, 0x01166d, 0x01167f, 0x0116b9, - 0x0116bf, 0x0116ca, 0x0116ff, 0x01171b, 0x01171c, 0x01172c, 0x01172f, 0x011740, 0x0117ff, 0x01183c, 0x01189f, 0x0118f3, 0x0118fe, 0x011907, 0x011908, 0x01190a, 0x01190b, - 0x011914, 0x011914, 0x011917, 0x011917, 0x011936, 0x011936, 0x011939, 0x01193a, 0x011947, 0x01194f, 0x01195a, 0x01199f, 0x0119a8, 0x0119a9, 0x0119d8, 0x0119d9, 0x0119e5, - 0x0119ff, 0x011a48, 0x011a4f, 0x011aa3, 0x011abf, 0x011af9, 0x011bff, 0x011c09, 0x011c09, 0x011c37, 0x011c37, 0x011c46, 0x011c4f, 0x011c6d, 0x011c6f, 0x011c90, 0x011c91, - 0x011ca8, 0x011ca8, 0x011cb7, 0x011cff, 0x011d07, 0x011d07, 0x011d0a, 0x011d0a, 0x011d37, 0x011d39, 0x011d3b, 0x011d3b, 0x011d3e, 0x011d3e, 0x011d48, 0x011d4f, 0x011d5a, - 0x011d5f, 0x011d66, 0x011d66, 0x011d69, 0x011d69, 0x011d8f, 0x011d8f, 0x011d92, 0x011d92, 0x011d99, 0x011d9f, 0x011daa, 0x011edf, 0x011ef9, 0x011faf, 0x011fb1, 0x011fbf, - 0x011ff2, 0x011ffe, 0x01239a, 0x0123ff, 0x01246f, 0x01246f, 0x012475, 0x01247f, 0x012544, 0x012fff, 0x01342f, 0x01342f, 0x013439, 0x0143ff, 0x014647, 0x0167ff, 0x016a39, - 0x016a3f, 0x016a5f, 0x016a5f, 0x016a6a, 0x016a6d, 0x016a70, 0x016acf, 0x016aee, 0x016aef, 0x016af6, 0x016aff, 0x016b46, 0x016b4f, 0x016b5a, 0x016b5a, 0x016b62, 0x016b62, - 0x016b78, 0x016b7c, 0x016b90, 0x016e3f, 0x016e9b, 0x016eff, 0x016f4b, 0x016f4e, 0x016f88, 0x016f8e, 0x016fa0, 0x016fdf, 0x016fe5, 0x016fef, 0x016ff2, 0x016fff, 0x0187f8, - 0x0187ff, 0x018cd6, 0x018cff, 0x018d09, 0x01afff, 0x01b11f, 0x01b14f, 0x01b153, 0x01b163, 0x01b168, 0x01b16f, 0x01b2fc, 0x01bbff, 0x01bc6b, 0x01bc6f, 0x01bc7d, 0x01bc7f, - 0x01bc89, 0x01bc8f, 0x01bc9a, 0x01bc9b, 0x01bca4, 0x01cfff, 0x01d0f6, 0x01d0ff, 0x01d127, 0x01d128, 0x01d1e9, 0x01d1ff, 0x01d246, 0x01d2df, 0x01d2f4, 0x01d2ff, 0x01d357, - 0x01d35f, 0x01d379, 0x01d3ff, 0x01d455, 0x01d455, 0x01d49d, 0x01d49d, 0x01d4a0, 0x01d4a1, 0x01d4a3, 0x01d4a4, 0x01d4a7, 0x01d4a8, 0x01d4ad, 0x01d4ad, 0x01d4ba, 0x01d4ba, - 0x01d4bc, 0x01d4bc, 0x01d4c4, 0x01d4c4, 0x01d506, 0x01d506, 0x01d50b, 0x01d50c, 0x01d515, 0x01d515, 0x01d51d, 0x01d51d, 0x01d53a, 0x01d53a, 0x01d53f, 0x01d53f, 0x01d545, - 0x01d545, 0x01d547, 0x01d549, 0x01d551, 0x01d551, 0x01d6a6, 0x01d6a7, 0x01d7cc, 0x01d7cd, 0x01da8c, 0x01da9a, 0x01daa0, 0x01daa0, 0x01dab0, 0x01dfff, 0x01e007, 0x01e007, - 0x01e019, 0x01e01a, 0x01e022, 0x01e022, 0x01e025, 0x01e025, 0x01e02b, 0x01e0ff, 0x01e12d, 0x01e12f, 0x01e13e, 0x01e13f, 0x01e14a, 0x01e14d, 0x01e150, 0x01e2bf, 0x01e2fa, - 0x01e2fe, 0x01e300, 0x01e7ff, 0x01e8c5, 0x01e8c6, 0x01e8d7, 0x01e8ff, 0x01e94c, 0x01e94f, 0x01e95a, 0x01e95d, 0x01e960, 0x01ec70, 0x01ecb5, 0x01ed00, 0x01ed3e, 0x01edff, - 0x01ee04, 0x01ee04, 0x01ee20, 0x01ee20, 0x01ee23, 0x01ee23, 0x01ee25, 0x01ee26, 0x01ee28, 0x01ee28, 0x01ee33, 0x01ee33, 0x01ee38, 0x01ee38, 0x01ee3a, 0x01ee3a, 0x01ee3c, - 0x01ee41, 0x01ee43, 0x01ee46, 0x01ee48, 0x01ee48, 0x01ee4a, 0x01ee4a, 0x01ee4c, 0x01ee4c, 0x01ee50, 0x01ee50, 0x01ee53, 0x01ee53, 0x01ee55, 0x01ee56, 0x01ee58, 0x01ee58, - 0x01ee5a, 0x01ee5a, 0x01ee5c, 0x01ee5c, 0x01ee5e, 0x01ee5e, 0x01ee60, 0x01ee60, 0x01ee63, 0x01ee63, 0x01ee65, 0x01ee66, 0x01ee6b, 0x01ee6b, 0x01ee73, 0x01ee73, 0x01ee78, - 0x01ee78, 0x01ee7d, 0x01ee7d, 0x01ee7f, 0x01ee7f, 0x01ee8a, 0x01ee8a, 0x01ee9c, 0x01eea0, 0x01eea4, 0x01eea4, 0x01eeaa, 0x01eeaa, 0x01eebc, 0x01eeef, 0x01eef2, 0x01efff, - 0x01f02c, 0x01f02f, 0x01f094, 0x01f09f, 0x01f0af, 0x01f0b0, 0x01f0c0, 0x01f0c0, 0x01f0d0, 0x01f0d0, 0x01f0f6, 0x01f0ff, 0x01f1ae, 0x01f1e5, 0x01f203, 0x01f20f, 0x01f23c, - 0x01f23f, 0x01f249, 0x01f24f, 0x01f252, 0x01f25f, 0x01f266, 0x01f2ff, 0x01f6d8, 0x01f6df, 0x01f6ed, 0x01f6ef, 0x01f6fd, 0x01f6ff, 0x01f774, 0x01f77f, 0x01f7d9, 0x01f7df, - 0x01f7ec, 0x01f7ff, 0x01f80c, 0x01f80f, 0x01f848, 0x01f84f, 0x01f85a, 0x01f85f, 0x01f888, 0x01f88f, 0x01f8ae, 0x01f8af, 0x01f8b2, 0x01f8ff, 0x01f979, 0x01f979, 0x01f9cc, - 0x01f9cc, 0x01fa54, 0x01fa5f, 0x01fa6e, 0x01fa6f, 0x01fa75, 0x01fa77, 0x01fa7b, 0x01fa7f, 0x01fa87, 0x01fa8f, 0x01faa9, 0x01faaf, 0x01fab7, 0x01fabf, 0x01fac3, 0x01facf, - 0x01fad7, 0x01faff, 0x01fb93, 0x01fb93, 0x01fbcb, 0x01fbef, 0x01fbfa, 0x01ffff, 0x02a6de, 0x02a6ff, 0x02b735, 0x02b73f, 0x02b81e, 0x02b81f, 0x02cea2, 0x02ceaf, 0x02ebe1, - 0x02f7ff, 0x02fa1e, 0x02ffff, 0x03134b, 0x0e0000, 0x0e0002, 0x0e001f, 0x0e0080, 0x0e00ff, 0x0e01f0, 0x10ffff)); + 0x001716, 0x00171e, 0x001737, 0x00173f, 0x001754, 0x00175f, 0x00176d, 0x00176d, 0x001771, 0x001771, 0x001774, 0x00177f, 0x0017de, 0x0017df, 0x0017ea, 0x0017ef, 0x0017fa, + 0x0017ff, 0x00181a, 0x00181f, 0x001879, 0x00187f, 0x0018ab, 0x0018af, 0x0018f6, 0x0018ff, 0x00191f, 0x00191f, 0x00192c, 0x00192f, 0x00193c, 0x00193f, 0x001941, 0x001943, + 0x00196e, 0x00196f, 0x001975, 0x00197f, 0x0019ac, 0x0019af, 0x0019ca, 0x0019cf, 0x0019db, 0x0019dd, 0x001a1c, 0x001a1d, 0x001a5f, 0x001a5f, 0x001a7d, 0x001a7e, 0x001a8a, + 0x001a8f, 0x001a9a, 0x001a9f, 0x001aae, 0x001aaf, 0x001acf, 0x001aff, 0x001b4d, 0x001b4f, 0x001b7f, 0x001b7f, 0x001bf4, 0x001bfb, 0x001c38, 0x001c3a, 0x001c4a, 0x001c4c, + 0x001c89, 0x001c8f, 0x001cbb, 0x001cbc, 0x001cc8, 0x001ccf, 0x001cfb, 0x001cff, 0x001f16, 0x001f17, 0x001f1e, 0x001f1f, 0x001f46, 0x001f47, 0x001f4e, 0x001f4f, 0x001f58, + 0x001f58, 0x001f5a, 0x001f5a, 0x001f5c, 0x001f5c, 0x001f5e, 0x001f5e, 0x001f7e, 0x001f7f, 0x001fb5, 0x001fb5, 0x001fc5, 0x001fc5, 0x001fd4, 0x001fd5, 0x001fdc, 0x001fdc, + 0x001ff0, 0x001ff1, 0x001ff5, 0x001ff5, 0x001fff, 0x001fff, 0x002065, 0x002065, 0x002072, 0x002073, 0x00208f, 0x00208f, 0x00209d, 0x00209f, 0x0020c1, 0x0020cf, 0x0020f1, + 0x0020ff, 0x00218c, 0x00218f, 0x002427, 0x00243f, 0x00244b, 0x00245f, 0x002b74, 0x002b75, 0x002b96, 0x002b96, 0x002cf4, 0x002cf8, 0x002d26, 0x002d26, 0x002d28, 0x002d2c, + 0x002d2e, 0x002d2f, 0x002d68, 0x002d6e, 0x002d71, 0x002d7e, 0x002d97, 0x002d9f, 0x002da7, 0x002da7, 0x002daf, 0x002daf, 0x002db7, 0x002db7, 0x002dbf, 0x002dbf, 0x002dc7, + 0x002dc7, 0x002dcf, 0x002dcf, 0x002dd7, 0x002dd7, 0x002ddf, 0x002ddf, 0x002e5e, 0x002e7f, 0x002e9a, 0x002e9a, 0x002ef4, 0x002eff, 0x002fd6, 0x002fef, 0x002ffc, 0x002fff, + 0x003040, 0x003040, 0x003097, 0x003098, 0x003100, 0x003104, 0x003130, 0x003130, 0x00318f, 0x00318f, 0x0031e4, 0x0031ef, 0x00321f, 0x00321f, 0x00a48d, 0x00a48f, 0x00a4c7, + 0x00a4cf, 0x00a62c, 0x00a63f, 0x00a6f8, 0x00a6ff, 0x00a7cb, 0x00a7cf, 0x00a7d2, 0x00a7d2, 0x00a7d4, 0x00a7d4, 0x00a7da, 0x00a7f1, 0x00a82d, 0x00a82f, 0x00a83a, 0x00a83f, + 0x00a878, 0x00a87f, 0x00a8c6, 0x00a8cd, 0x00a8da, 0x00a8df, 0x00a954, 0x00a95e, 0x00a97d, 0x00a97f, 0x00a9ce, 0x00a9ce, 0x00a9da, 0x00a9dd, 0x00a9ff, 0x00a9ff, 0x00aa37, + 0x00aa3f, 0x00aa4e, 0x00aa4f, 0x00aa5a, 0x00aa5b, 0x00aac3, 0x00aada, 0x00aaf7, 0x00ab00, 0x00ab07, 0x00ab08, 0x00ab0f, 0x00ab10, 0x00ab17, 0x00ab1f, 0x00ab27, 0x00ab27, + 0x00ab2f, 0x00ab2f, 0x00ab6c, 0x00ab6f, 0x00abee, 0x00abef, 0x00abfa, 0x00abff, 0x00d7a4, 0x00d7af, 0x00d7c7, 0x00d7ca, 0x00d7fc, 0x00f8ff, 0x00fa6e, 0x00fa6f, 0x00fada, + 0x00faff, 0x00fb07, 0x00fb12, 0x00fb18, 0x00fb1c, 0x00fb37, 0x00fb37, 0x00fb3d, 0x00fb3d, 0x00fb3f, 0x00fb3f, 0x00fb42, 0x00fb42, 0x00fb45, 0x00fb45, 0x00fbc3, 0x00fbd2, + 0x00fd90, 0x00fd91, 0x00fdc8, 0x00fdce, 0x00fdd0, 0x00fdef, 0x00fe1a, 0x00fe1f, 0x00fe53, 0x00fe53, 0x00fe67, 0x00fe67, 0x00fe6c, 0x00fe6f, 0x00fe75, 0x00fe75, 0x00fefd, + 0x00fefe, 0x00ff00, 0x00ff00, 0x00ffbf, 0x00ffc1, 0x00ffc8, 0x00ffc9, 0x00ffd0, 0x00ffd1, 0x00ffd8, 0x00ffd9, 0x00ffdd, 0x00ffdf, 0x00ffe7, 0x00ffe7, 0x00ffef, 0x00fff8, + 0x00fffe, 0x00ffff, 0x01000c, 0x01000c, 0x010027, 0x010027, 0x01003b, 0x01003b, 0x01003e, 0x01003e, 0x01004e, 0x01004f, 0x01005e, 0x01007f, 0x0100fb, 0x0100ff, 0x010103, + 0x010106, 0x010134, 0x010136, 0x01018f, 0x01018f, 0x01019d, 0x01019f, 0x0101a1, 0x0101cf, 0x0101fe, 0x01027f, 0x01029d, 0x01029f, 0x0102d1, 0x0102df, 0x0102fc, 0x0102ff, + 0x010324, 0x01032c, 0x01034b, 0x01034f, 0x01037b, 0x01037f, 0x01039e, 0x01039e, 0x0103c4, 0x0103c7, 0x0103d6, 0x0103ff, 0x01049e, 0x01049f, 0x0104aa, 0x0104af, 0x0104d4, + 0x0104d7, 0x0104fc, 0x0104ff, 0x010528, 0x01052f, 0x010564, 0x01056e, 0x01057b, 0x01057b, 0x01058b, 0x01058b, 0x010593, 0x010593, 0x010596, 0x010596, 0x0105a2, 0x0105a2, + 0x0105b2, 0x0105b2, 0x0105ba, 0x0105ba, 0x0105bd, 0x0105ff, 0x010737, 0x01073f, 0x010756, 0x01075f, 0x010768, 0x01077f, 0x010786, 0x010786, 0x0107b1, 0x0107b1, 0x0107bb, + 0x0107ff, 0x010806, 0x010807, 0x010809, 0x010809, 0x010836, 0x010836, 0x010839, 0x01083b, 0x01083d, 0x01083e, 0x010856, 0x010856, 0x01089f, 0x0108a6, 0x0108b0, 0x0108df, + 0x0108f3, 0x0108f3, 0x0108f6, 0x0108fa, 0x01091c, 0x01091e, 0x01093a, 0x01093e, 0x010940, 0x01097f, 0x0109b8, 0x0109bb, 0x0109d0, 0x0109d1, 0x010a04, 0x010a04, 0x010a07, + 0x010a0b, 0x010a14, 0x010a14, 0x010a18, 0x010a18, 0x010a36, 0x010a37, 0x010a3b, 0x010a3e, 0x010a49, 0x010a4f, 0x010a59, 0x010a5f, 0x010aa0, 0x010abf, 0x010ae7, 0x010aea, + 0x010af7, 0x010aff, 0x010b36, 0x010b38, 0x010b56, 0x010b57, 0x010b73, 0x010b77, 0x010b92, 0x010b98, 0x010b9d, 0x010ba8, 0x010bb0, 0x010bff, 0x010c49, 0x010c7f, 0x010cb3, + 0x010cbf, 0x010cf3, 0x010cf9, 0x010d28, 0x010d2f, 0x010d3a, 0x010e5f, 0x010e7f, 0x010e7f, 0x010eaa, 0x010eaa, 0x010eae, 0x010eaf, 0x010eb2, 0x010eff, 0x010f28, 0x010f2f, + 0x010f5a, 0x010f6f, 0x010f8a, 0x010faf, 0x010fcc, 0x010fdf, 0x010ff7, 0x010fff, 0x01104e, 0x011051, 0x011076, 0x01107e, 0x0110c3, 0x0110cc, 0x0110ce, 0x0110cf, 0x0110e9, + 0x0110ef, 0x0110fa, 0x0110ff, 0x011135, 0x011135, 0x011148, 0x01114f, 0x011177, 0x01117f, 0x0111e0, 0x0111e0, 0x0111f5, 0x0111ff, 0x011212, 0x011212, 0x01123f, 0x01127f, + 0x011287, 0x011287, 0x011289, 0x011289, 0x01128e, 0x01128e, 0x01129e, 0x01129e, 0x0112aa, 0x0112af, 0x0112eb, 0x0112ef, 0x0112fa, 0x0112ff, 0x011304, 0x011304, 0x01130d, + 0x01130e, 0x011311, 0x011312, 0x011329, 0x011329, 0x011331, 0x011331, 0x011334, 0x011334, 0x01133a, 0x01133a, 0x011345, 0x011346, 0x011349, 0x01134a, 0x01134e, 0x01134f, + 0x011351, 0x011356, 0x011358, 0x01135c, 0x011364, 0x011365, 0x01136d, 0x01136f, 0x011375, 0x0113ff, 0x01145c, 0x01145c, 0x011462, 0x01147f, 0x0114c8, 0x0114cf, 0x0114da, + 0x01157f, 0x0115b6, 0x0115b7, 0x0115de, 0x0115ff, 0x011645, 0x01164f, 0x01165a, 0x01165f, 0x01166d, 0x01167f, 0x0116ba, 0x0116bf, 0x0116ca, 0x0116ff, 0x01171b, 0x01171c, + 0x01172c, 0x01172f, 0x011747, 0x0117ff, 0x01183c, 0x01189f, 0x0118f3, 0x0118fe, 0x011907, 0x011908, 0x01190a, 0x01190b, 0x011914, 0x011914, 0x011917, 0x011917, 0x011936, + 0x011936, 0x011939, 0x01193a, 0x011947, 0x01194f, 0x01195a, 0x01199f, 0x0119a8, 0x0119a9, 0x0119d8, 0x0119d9, 0x0119e5, 0x0119ff, 0x011a48, 0x011a4f, 0x011aa3, 0x011aaf, + 0x011af9, 0x011bff, 0x011c09, 0x011c09, 0x011c37, 0x011c37, 0x011c46, 0x011c4f, 0x011c6d, 0x011c6f, 0x011c90, 0x011c91, 0x011ca8, 0x011ca8, 0x011cb7, 0x011cff, 0x011d07, + 0x011d07, 0x011d0a, 0x011d0a, 0x011d37, 0x011d39, 0x011d3b, 0x011d3b, 0x011d3e, 0x011d3e, 0x011d48, 0x011d4f, 0x011d5a, 0x011d5f, 0x011d66, 0x011d66, 0x011d69, 0x011d69, + 0x011d8f, 0x011d8f, 0x011d92, 0x011d92, 0x011d99, 0x011d9f, 0x011daa, 0x011edf, 0x011ef9, 0x011faf, 0x011fb1, 0x011fbf, 0x011ff2, 0x011ffe, 0x01239a, 0x0123ff, 0x01246f, + 0x01246f, 0x012475, 0x01247f, 0x012544, 0x012f8f, 0x012ff3, 0x012fff, 0x01342f, 0x01342f, 0x013439, 0x0143ff, 0x014647, 0x0167ff, 0x016a39, 0x016a3f, 0x016a5f, 0x016a5f, + 0x016a6a, 0x016a6d, 0x016abf, 0x016abf, 0x016aca, 0x016acf, 0x016aee, 0x016aef, 0x016af6, 0x016aff, 0x016b46, 0x016b4f, 0x016b5a, 0x016b5a, 0x016b62, 0x016b62, 0x016b78, + 0x016b7c, 0x016b90, 0x016e3f, 0x016e9b, 0x016eff, 0x016f4b, 0x016f4e, 0x016f88, 0x016f8e, 0x016fa0, 0x016fdf, 0x016fe5, 0x016fef, 0x016ff2, 0x016fff, 0x0187f8, 0x0187ff, + 0x018cd6, 0x018cff, 0x018d09, 0x01afef, 0x01aff4, 0x01aff4, 0x01affc, 0x01affc, 0x01afff, 0x01afff, 0x01b123, 0x01b14f, 0x01b153, 0x01b163, 0x01b168, 0x01b16f, 0x01b2fc, + 0x01bbff, 0x01bc6b, 0x01bc6f, 0x01bc7d, 0x01bc7f, 0x01bc89, 0x01bc8f, 0x01bc9a, 0x01bc9b, 0x01bca4, 0x01ceff, 0x01cf2e, 0x01cf2f, 0x01cf47, 0x01cf4f, 0x01cfc4, 0x01cfff, + 0x01d0f6, 0x01d0ff, 0x01d127, 0x01d128, 0x01d1eb, 0x01d1ff, 0x01d246, 0x01d2df, 0x01d2f4, 0x01d2ff, 0x01d357, 0x01d35f, 0x01d379, 0x01d3ff, 0x01d455, 0x01d455, 0x01d49d, + 0x01d49d, 0x01d4a0, 0x01d4a1, 0x01d4a3, 0x01d4a4, 0x01d4a7, 0x01d4a8, 0x01d4ad, 0x01d4ad, 0x01d4ba, 0x01d4ba, 0x01d4bc, 0x01d4bc, 0x01d4c4, 0x01d4c4, 0x01d506, 0x01d506, + 0x01d50b, 0x01d50c, 0x01d515, 0x01d515, 0x01d51d, 0x01d51d, 0x01d53a, 0x01d53a, 0x01d53f, 0x01d53f, 0x01d545, 0x01d545, 0x01d547, 0x01d549, 0x01d551, 0x01d551, 0x01d6a6, + 0x01d6a7, 0x01d7cc, 0x01d7cd, 0x01da8c, 0x01da9a, 0x01daa0, 0x01daa0, 0x01dab0, 0x01deff, 0x01df1f, 0x01dfff, 0x01e007, 0x01e007, 0x01e019, 0x01e01a, 0x01e022, 0x01e022, + 0x01e025, 0x01e025, 0x01e02b, 0x01e0ff, 0x01e12d, 0x01e12f, 0x01e13e, 0x01e13f, 0x01e14a, 0x01e14d, 0x01e150, 0x01e28f, 0x01e2af, 0x01e2bf, 0x01e2fa, 0x01e2fe, 0x01e300, + 0x01e7df, 0x01e7e7, 0x01e7e7, 0x01e7ec, 0x01e7ec, 0x01e7ef, 0x01e7ef, 0x01e7ff, 0x01e7ff, 0x01e8c5, 0x01e8c6, 0x01e8d7, 0x01e8ff, 0x01e94c, 0x01e94f, 0x01e95a, 0x01e95d, + 0x01e960, 0x01ec70, 0x01ecb5, 0x01ed00, 0x01ed3e, 0x01edff, 0x01ee04, 0x01ee04, 0x01ee20, 0x01ee20, 0x01ee23, 0x01ee23, 0x01ee25, 0x01ee26, 0x01ee28, 0x01ee28, 0x01ee33, + 0x01ee33, 0x01ee38, 0x01ee38, 0x01ee3a, 0x01ee3a, 0x01ee3c, 0x01ee41, 0x01ee43, 0x01ee46, 0x01ee48, 0x01ee48, 0x01ee4a, 0x01ee4a, 0x01ee4c, 0x01ee4c, 0x01ee50, 0x01ee50, + 0x01ee53, 0x01ee53, 0x01ee55, 0x01ee56, 0x01ee58, 0x01ee58, 0x01ee5a, 0x01ee5a, 0x01ee5c, 0x01ee5c, 0x01ee5e, 0x01ee5e, 0x01ee60, 0x01ee60, 0x01ee63, 0x01ee63, 0x01ee65, + 0x01ee66, 0x01ee6b, 0x01ee6b, 0x01ee73, 0x01ee73, 0x01ee78, 0x01ee78, 0x01ee7d, 0x01ee7d, 0x01ee7f, 0x01ee7f, 0x01ee8a, 0x01ee8a, 0x01ee9c, 0x01eea0, 0x01eea4, 0x01eea4, + 0x01eeaa, 0x01eeaa, 0x01eebc, 0x01eeef, 0x01eef2, 0x01efff, 0x01f02c, 0x01f02f, 0x01f094, 0x01f09f, 0x01f0af, 0x01f0b0, 0x01f0c0, 0x01f0c0, 0x01f0d0, 0x01f0d0, 0x01f0f6, + 0x01f0ff, 0x01f1ae, 0x01f1e5, 0x01f203, 0x01f20f, 0x01f23c, 0x01f23f, 0x01f249, 0x01f24f, 0x01f252, 0x01f25f, 0x01f266, 0x01f2ff, 0x01f6d8, 0x01f6dc, 0x01f6ed, 0x01f6ef, + 0x01f6fd, 0x01f6ff, 0x01f774, 0x01f77f, 0x01f7d9, 0x01f7df, 0x01f7ec, 0x01f7ef, 0x01f7f1, 0x01f7ff, 0x01f80c, 0x01f80f, 0x01f848, 0x01f84f, 0x01f85a, 0x01f85f, 0x01f888, + 0x01f88f, 0x01f8ae, 0x01f8af, 0x01f8b2, 0x01f8ff, 0x01fa54, 0x01fa5f, 0x01fa6e, 0x01fa6f, 0x01fa75, 0x01fa77, 0x01fa7d, 0x01fa7f, 0x01fa87, 0x01fa8f, 0x01faad, 0x01faaf, + 0x01fabb, 0x01fabf, 0x01fac6, 0x01facf, 0x01fada, 0x01fadf, 0x01fae8, 0x01faef, 0x01faf7, 0x01faff, 0x01fb93, 0x01fb93, 0x01fbcb, 0x01fbef, 0x01fbfa, 0x01ffff, 0x02a6e0, + 0x02a6ff, 0x02b739, 0x02b73f, 0x02b81e, 0x02b81f, 0x02cea2, 0x02ceaf, 0x02ebe1, 0x02f7ff, 0x02fa1e, 0x02ffff, 0x03134b, 0x0e0000, 0x0e0002, 0x0e001f, 0x0e0080, 0x0e00ff, + 0x0e01f0, 0x10ffff)); } } diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nodes/TRegexExecNode.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nodes/TRegexExecNode.java index b5477d6f7e43..b97cfd5c168b 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nodes/TRegexExecNode.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nodes/TRegexExecNode.java @@ -43,7 +43,6 @@ import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.regex.RegexBodyNode; @@ -408,7 +407,7 @@ public LazyCaptureGroupRegexSearchNode(RegexLanguage language, } else { bodyNode = new TRegexLazyFindStartRootNode(language, source, backwardNode, captureGroupNode == null); } - backwardCallTarget = Truffle.getRuntime().createCallTarget(new RegexRootNode(language, bodyNode)); + backwardCallTarget = new RegexRootNode(language, bodyNode).getCallTarget(); } this.captureGroupEntryNode = insert(captureGroupNode); if (captureGroupNode == null) { @@ -420,8 +419,7 @@ public LazyCaptureGroupRegexSearchNode(RegexLanguage language, } else { findStartCallTarget = backwardCallTarget; } - captureGroupCallTarget = Truffle.getRuntime().createCallTarget( - new RegexRootNode(language, new TRegexLazyCaptureGroupsRootNode(language, source, captureGroupNode, rootNode, findStartCallTarget))); + captureGroupCallTarget = new RegexRootNode(language, new TRegexLazyCaptureGroupsRootNode(language, source, captureGroupNode, rootNode, findStartCallTarget)).getCallTarget(); } } diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nodes/TRegexExecutorNode.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nodes/TRegexExecutorNode.java index 36fbe87585c0..240d3d0871ae 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nodes/TRegexExecutorNode.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nodes/TRegexExecutorNode.java @@ -182,7 +182,7 @@ public int inputReadAndDecode(TRegexExecutorLocals locals, int index) { return codepoint | (c & (0xff >>> nBytes)) << (6 * (nBytes - 1)); } } else { - assert getEncoding() == Encodings.UTF_16_RAW || getEncoding() == Encodings.UTF_32 || getEncoding() == Encodings.LATIN_1; + assert getEncoding() == Encodings.UTF_16_RAW || getEncoding() == Encodings.UTF_32 || getEncoding() == Encodings.LATIN_1 || getEncoding() == Encodings.ASCII; locals.setNextIndex(inputIncRaw(index)); return inputReadRaw(locals); } @@ -261,7 +261,7 @@ protected void inputSkipIntl(TRegexExecutorLocals locals, boolean forward) { } while (inputHasNext(locals, false) && inputUTF8IsTrailingByte(c)); } } else { - assert getEncoding() == Encodings.UTF_16_RAW || getEncoding() == Encodings.UTF_32 || getEncoding() == Encodings.LATIN_1; + assert getEncoding() == Encodings.UTF_16_RAW || getEncoding() == Encodings.UTF_32 || getEncoding() == Encodings.LATIN_1 || getEncoding() == Encodings.ASCII; inputIncRaw(locals, forward); } } diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/CaseFoldTable.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/CaseFoldTable.java index 73131fc51010..2589cef46975 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/CaseFoldTable.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/CaseFoldTable.java @@ -579,8 +579,8 @@ public void appendRangesTo(RangesBuffer buffer, int startIndex, int endIndex) { 0x002183, 0x002184, ALTERNATING_UL, 0, 0x0024b6, 0x0024cf, INTEGER_OFFSET, 26, 0x0024d0, 0x0024e9, INTEGER_OFFSET, -26, - 0x002c00, 0x002c2e, INTEGER_OFFSET, 48, - 0x002c30, 0x002c5e, INTEGER_OFFSET, -48, + 0x002c00, 0x002c2f, INTEGER_OFFSET, 48, + 0x002c30, 0x002c5f, INTEGER_OFFSET, -48, 0x002c60, 0x002c61, ALTERNATING_AL, 0, 0x002c62, 0x002c62, INTEGER_OFFSET, -10743, 0x002c63, 0x002c63, INTEGER_OFFSET, -3814, @@ -624,12 +624,13 @@ public void appendRangesTo(RangesBuffer buffer, int startIndex, int endIndex) { 0x00a7b1, 0x00a7b1, INTEGER_OFFSET, -42282, 0x00a7b2, 0x00a7b2, INTEGER_OFFSET, -42261, 0x00a7b3, 0x00a7b3, INTEGER_OFFSET, 928, - 0x00a7b4, 0x00a7bf, ALTERNATING_AL, 0, - 0x00a7c2, 0x00a7c3, ALTERNATING_AL, 0, + 0x00a7b4, 0x00a7c3, ALTERNATING_AL, 0, 0x00a7c4, 0x00a7c4, INTEGER_OFFSET, -48, 0x00a7c5, 0x00a7c5, INTEGER_OFFSET, -42307, 0x00a7c6, 0x00a7c6, INTEGER_OFFSET, -35384, 0x00a7c7, 0x00a7ca, ALTERNATING_UL, 0, + 0x00a7d0, 0x00a7d1, ALTERNATING_AL, 0, + 0x00a7d6, 0x00a7d9, ALTERNATING_AL, 0, 0x00a7f5, 0x00a7f6, ALTERNATING_UL, 0, 0x00ab53, 0x00ab53, INTEGER_OFFSET, -928, 0x00ab70, 0x00abbf, INTEGER_OFFSET, -38864, @@ -639,6 +640,14 @@ public void appendRangesTo(RangesBuffer buffer, int startIndex, int endIndex) { 0x010428, 0x01044f, INTEGER_OFFSET, -40, 0x0104b0, 0x0104d3, INTEGER_OFFSET, 40, 0x0104d8, 0x0104fb, INTEGER_OFFSET, -40, + 0x010570, 0x01057a, INTEGER_OFFSET, 39, + 0x01057c, 0x01058a, INTEGER_OFFSET, 39, + 0x01058c, 0x010592, INTEGER_OFFSET, 39, + 0x010594, 0x010595, INTEGER_OFFSET, 39, + 0x010597, 0x0105a1, INTEGER_OFFSET, -39, + 0x0105a3, 0x0105b1, INTEGER_OFFSET, -39, + 0x0105b3, 0x0105b9, INTEGER_OFFSET, -39, + 0x0105bb, 0x0105bc, INTEGER_OFFSET, -39, 0x010c80, 0x010cb2, INTEGER_OFFSET, 64, 0x010cc0, 0x010cf2, INTEGER_OFFSET, -64, 0x0118a0, 0x0118bf, INTEGER_OFFSET, 32, @@ -965,8 +974,8 @@ public void appendRangesTo(RangesBuffer buffer, int startIndex, int endIndex) { 0x002183, 0x002184, ALTERNATING_UL, 0, 0x0024b6, 0x0024cf, INTEGER_OFFSET, 26, 0x0024d0, 0x0024e9, INTEGER_OFFSET, -26, - 0x002c00, 0x002c2e, INTEGER_OFFSET, 48, - 0x002c30, 0x002c5e, INTEGER_OFFSET, -48, + 0x002c00, 0x002c2f, INTEGER_OFFSET, 48, + 0x002c30, 0x002c5f, INTEGER_OFFSET, -48, 0x002c60, 0x002c61, ALTERNATING_AL, 0, 0x002c62, 0x002c62, INTEGER_OFFSET, -10743, 0x002c63, 0x002c63, INTEGER_OFFSET, -3814, @@ -1010,12 +1019,13 @@ public void appendRangesTo(RangesBuffer buffer, int startIndex, int endIndex) { 0x00a7b1, 0x00a7b1, INTEGER_OFFSET, -42282, 0x00a7b2, 0x00a7b2, INTEGER_OFFSET, -42261, 0x00a7b3, 0x00a7b3, INTEGER_OFFSET, 928, - 0x00a7b4, 0x00a7bf, ALTERNATING_AL, 0, - 0x00a7c2, 0x00a7c3, ALTERNATING_AL, 0, + 0x00a7b4, 0x00a7c3, ALTERNATING_AL, 0, 0x00a7c4, 0x00a7c4, INTEGER_OFFSET, -48, 0x00a7c5, 0x00a7c5, INTEGER_OFFSET, -42307, 0x00a7c6, 0x00a7c6, INTEGER_OFFSET, -35384, 0x00a7c7, 0x00a7ca, ALTERNATING_UL, 0, + 0x00a7d0, 0x00a7d1, ALTERNATING_AL, 0, + 0x00a7d6, 0x00a7d9, ALTERNATING_AL, 0, 0x00a7f5, 0x00a7f6, ALTERNATING_UL, 0, 0x00ab53, 0x00ab53, INTEGER_OFFSET, -928, 0x00ab70, 0x00abbf, INTEGER_OFFSET, -38864, @@ -1025,6 +1035,14 @@ public void appendRangesTo(RangesBuffer buffer, int startIndex, int endIndex) { 0x010428, 0x01044f, INTEGER_OFFSET, -40, 0x0104b0, 0x0104d3, INTEGER_OFFSET, 40, 0x0104d8, 0x0104fb, INTEGER_OFFSET, -40, + 0x010570, 0x01057a, INTEGER_OFFSET, 39, + 0x01057c, 0x01058a, INTEGER_OFFSET, 39, + 0x01058c, 0x010592, INTEGER_OFFSET, 39, + 0x010594, 0x010595, INTEGER_OFFSET, 39, + 0x010597, 0x0105a1, INTEGER_OFFSET, -39, + 0x0105a3, 0x0105b1, INTEGER_OFFSET, -39, + 0x0105b3, 0x0105b9, INTEGER_OFFSET, -39, + 0x0105bb, 0x0105bc, INTEGER_OFFSET, -39, 0x010c80, 0x010cb2, INTEGER_OFFSET, 64, 0x010cc0, 0x010cf2, INTEGER_OFFSET, -64, 0x0118a0, 0x0118bf, INTEGER_OFFSET, 32, @@ -1528,8 +1546,8 @@ public void appendRangesTo(RangesBuffer buffer, int startIndex, int endIndex) { 0x002183, 0x002184, ALTERNATING_UL, 0, 0x0024b6, 0x0024cf, INTEGER_OFFSET, 26, 0x0024d0, 0x0024e9, INTEGER_OFFSET, -26, - 0x002c00, 0x002c2e, INTEGER_OFFSET, 48, - 0x002c30, 0x002c5e, INTEGER_OFFSET, -48, + 0x002c00, 0x002c2f, INTEGER_OFFSET, 48, + 0x002c30, 0x002c5f, INTEGER_OFFSET, -48, 0x002c60, 0x002c61, ALTERNATING_AL, 0, 0x002c62, 0x002c62, INTEGER_OFFSET, -10743, 0x002c63, 0x002c63, INTEGER_OFFSET, -3814, @@ -1573,12 +1591,13 @@ public void appendRangesTo(RangesBuffer buffer, int startIndex, int endIndex) { 0x00a7b1, 0x00a7b1, INTEGER_OFFSET, -42282, 0x00a7b2, 0x00a7b2, INTEGER_OFFSET, -42261, 0x00a7b3, 0x00a7b3, INTEGER_OFFSET, 928, - 0x00a7b4, 0x00a7bf, ALTERNATING_AL, 0, - 0x00a7c2, 0x00a7c3, ALTERNATING_AL, 0, + 0x00a7b4, 0x00a7c3, ALTERNATING_AL, 0, 0x00a7c4, 0x00a7c4, INTEGER_OFFSET, -48, 0x00a7c5, 0x00a7c5, INTEGER_OFFSET, -42307, 0x00a7c6, 0x00a7c6, INTEGER_OFFSET, -35384, 0x00a7c7, 0x00a7ca, ALTERNATING_UL, 0, + 0x00a7d0, 0x00a7d1, ALTERNATING_AL, 0, + 0x00a7d6, 0x00a7d9, ALTERNATING_AL, 0, 0x00a7f5, 0x00a7f6, ALTERNATING_UL, 0, 0x00ab53, 0x00ab53, INTEGER_OFFSET, -928, 0x00ab70, 0x00abbf, INTEGER_OFFSET, -38864, @@ -1593,6 +1612,14 @@ public void appendRangesTo(RangesBuffer buffer, int startIndex, int endIndex) { 0x010428, 0x01044f, INTEGER_OFFSET, -40, 0x0104b0, 0x0104d3, INTEGER_OFFSET, 40, 0x0104d8, 0x0104fb, INTEGER_OFFSET, -40, + 0x010570, 0x01057a, INTEGER_OFFSET, 39, + 0x01057c, 0x01058a, INTEGER_OFFSET, 39, + 0x01058c, 0x010592, INTEGER_OFFSET, 39, + 0x010594, 0x010595, INTEGER_OFFSET, 39, + 0x010597, 0x0105a1, INTEGER_OFFSET, -39, + 0x0105a3, 0x0105b1, INTEGER_OFFSET, -39, + 0x0105b3, 0x0105b9, INTEGER_OFFSET, -39, + 0x0105bb, 0x0105bc, INTEGER_OFFSET, -39, 0x010c80, 0x010cb2, INTEGER_OFFSET, 64, 0x010cc0, 0x010cf2, INTEGER_OFFSET, -64, 0x0118a0, 0x0118bf, INTEGER_OFFSET, 32, diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/flavors/RubyCaseFoldingData.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/flavors/RubyCaseFoldingData.java index 5ff5eca0e68b..4efcb62e609d 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/flavors/RubyCaseFoldingData.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/flavors/RubyCaseFoldingData.java @@ -1010,6 +1010,7 @@ public class RubyCaseFoldingData { CASE_FOLD.put(0x2C2C, new int[]{0x2C5C}); CASE_FOLD.put(0x2C2D, new int[]{0x2C5D}); CASE_FOLD.put(0x2C2E, new int[]{0x2C5E}); + CASE_FOLD.put(0x2C2F, new int[]{0x2C5F}); CASE_FOLD.put(0x2C60, new int[]{0x2C61}); CASE_FOLD.put(0x2C62, new int[]{0x026B}); CASE_FOLD.put(0x2C63, new int[]{0x1D7D}); @@ -1190,12 +1191,16 @@ public class RubyCaseFoldingData { CASE_FOLD.put(0xA7BA, new int[]{0xA7BB}); CASE_FOLD.put(0xA7BC, new int[]{0xA7BD}); CASE_FOLD.put(0xA7BE, new int[]{0xA7BF}); + CASE_FOLD.put(0xA7C0, new int[]{0xA7C1}); CASE_FOLD.put(0xA7C2, new int[]{0xA7C3}); CASE_FOLD.put(0xA7C4, new int[]{0xA794}); CASE_FOLD.put(0xA7C5, new int[]{0x0282}); CASE_FOLD.put(0xA7C6, new int[]{0x1D8E}); CASE_FOLD.put(0xA7C7, new int[]{0xA7C8}); CASE_FOLD.put(0xA7C9, new int[]{0xA7CA}); + CASE_FOLD.put(0xA7D0, new int[]{0xA7D1}); + CASE_FOLD.put(0xA7D6, new int[]{0xA7D7}); + CASE_FOLD.put(0xA7D8, new int[]{0xA7D9}); CASE_FOLD.put(0xA7F5, new int[]{0xA7F6}); CASE_FOLD.put(0xAB70, new int[]{0x13A0}); CASE_FOLD.put(0xAB71, new int[]{0x13A1}); @@ -1391,6 +1396,41 @@ public class RubyCaseFoldingData { CASE_FOLD.put(0x104D1, new int[]{0x104F9}); CASE_FOLD.put(0x104D2, new int[]{0x104FA}); CASE_FOLD.put(0x104D3, new int[]{0x104FB}); + CASE_FOLD.put(0x10570, new int[]{0x10597}); + CASE_FOLD.put(0x10571, new int[]{0x10598}); + CASE_FOLD.put(0x10572, new int[]{0x10599}); + CASE_FOLD.put(0x10573, new int[]{0x1059A}); + CASE_FOLD.put(0x10574, new int[]{0x1059B}); + CASE_FOLD.put(0x10575, new int[]{0x1059C}); + CASE_FOLD.put(0x10576, new int[]{0x1059D}); + CASE_FOLD.put(0x10577, new int[]{0x1059E}); + CASE_FOLD.put(0x10578, new int[]{0x1059F}); + CASE_FOLD.put(0x10579, new int[]{0x105A0}); + CASE_FOLD.put(0x1057A, new int[]{0x105A1}); + CASE_FOLD.put(0x1057C, new int[]{0x105A3}); + CASE_FOLD.put(0x1057D, new int[]{0x105A4}); + CASE_FOLD.put(0x1057E, new int[]{0x105A5}); + CASE_FOLD.put(0x1057F, new int[]{0x105A6}); + CASE_FOLD.put(0x10580, new int[]{0x105A7}); + CASE_FOLD.put(0x10581, new int[]{0x105A8}); + CASE_FOLD.put(0x10582, new int[]{0x105A9}); + CASE_FOLD.put(0x10583, new int[]{0x105AA}); + CASE_FOLD.put(0x10584, new int[]{0x105AB}); + CASE_FOLD.put(0x10585, new int[]{0x105AC}); + CASE_FOLD.put(0x10586, new int[]{0x105AD}); + CASE_FOLD.put(0x10587, new int[]{0x105AE}); + CASE_FOLD.put(0x10588, new int[]{0x105AF}); + CASE_FOLD.put(0x10589, new int[]{0x105B0}); + CASE_FOLD.put(0x1058A, new int[]{0x105B1}); + CASE_FOLD.put(0x1058C, new int[]{0x105B3}); + CASE_FOLD.put(0x1058D, new int[]{0x105B4}); + CASE_FOLD.put(0x1058E, new int[]{0x105B5}); + CASE_FOLD.put(0x1058F, new int[]{0x105B6}); + CASE_FOLD.put(0x10590, new int[]{0x105B7}); + CASE_FOLD.put(0x10591, new int[]{0x105B8}); + CASE_FOLD.put(0x10592, new int[]{0x105B9}); + CASE_FOLD.put(0x10594, new int[]{0x105BB}); + CASE_FOLD.put(0x10595, new int[]{0x105BC}); CASE_FOLD.put(0x10C80, new int[]{0x10CC0}); CASE_FOLD.put(0x10C81, new int[]{0x10CC1}); CASE_FOLD.put(0x10C82, new int[]{0x10CC2}); diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/flavors/RubyFlavorProcessor.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/flavors/RubyFlavorProcessor.java index e75d986e8c0c..74c7823fedf4 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/flavors/RubyFlavorProcessor.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/flavors/RubyFlavorProcessor.java @@ -1088,10 +1088,18 @@ private void escape() { } private CodePointSet getUnicodeCharClass(char className) { + if (inSource.getEncoding() == Encodings.ASCII) { + return ASCII_CHAR_CLASSES.get(className); + } + return trimToEncoding(UNICODE_CHAR_CLASSES.get(className)); } private CodePointSet getUnicodePosixCharClass(String className) { + if (inSource.getEncoding() == Encodings.ASCII) { + return ASCII_POSIX_CHAR_CLASSES.get(className); + } + return trimToEncoding(UNICODE_POSIX_CHAR_CLASSES.get(className)); } diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/string/Encodings.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/string/Encodings.java index 68a716a77458..8b8f2caf4a88 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/string/Encodings.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/string/Encodings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -62,8 +62,9 @@ public final class Encodings { public static final Encoding UTF_32 = new Encoding.UTF32(); public static final Encoding UTF_16_RAW = new Encoding.UTF16Raw(); public static final Encoding LATIN_1 = new Encoding.Latin1(); + public static final Encoding ASCII = new Encoding.Ascii(); - public static final String[] ALL_NAMES = {UTF_8.getName(), UTF_16.getName(), UTF_16_RAW.getName(), UTF_32.getName(), LATIN_1.getName(), "BYTES"}; + public static final String[] ALL_NAMES = {UTF_8.getName(), UTF_16.getName(), UTF_16_RAW.getName(), UTF_32.getName(), ASCII.getName(), LATIN_1.getName(), "BYTES"}; public static Encoding getEncoding(String name) { switch (name) { @@ -518,5 +519,63 @@ public Matchers toMatchers(Builder matchersBuilder) { return new Matchers.SimpleMatchers(matchersBuilder.materialize(0), matchersBuilder.getNoMatchSuccessor()); } } + + public static final class Ascii extends Encoding { + + @Override + public String getName() { + return "ASCII"; + } + + @Override + public int getMaxValue() { + return 0x7f; + } + + @Override + public CodePointSet getFullSet() { + return Constants.ASCII_RANGE; + } + + @Override + public int getEncodedSize(int codepoint) { + return 1; + } + + @Override + public boolean isFixedCodePointWidth(CodePointSet set) { + return true; + } + + @Override + public boolean isUnicode() { + return false; + } + + @Override + public AbstractStringBuffer createStringBuffer(int capacity) { + return new StringBufferASCII(capacity); + } + + @Override + public LoopOptimizationNode extractLoopOptNode(CodePointSet cps) { + return new LoopOptIndexOfAnyByteNode(cps.inverseToByteArray(this)); + } + + @Override + public int getNumberOfDecodingSteps() { + return 1; + } + + @Override + public void createMatcher(Builder matchersBuilder, int i, CodePointSet cps, CompilationBuffer compilationBuffer) { + matchersBuilder.getBuffer(0).set(i, CharMatchers.createMatcher(cps, compilationBuffer)); + } + + @Override + public Matchers toMatchers(Builder matchersBuilder) { + return new Matchers.SimpleMatchers(matchersBuilder.materialize(0), matchersBuilder.getNoMatchSuccessor()); + } + } } } diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/string/StringASCII.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/string/StringASCII.java new file mode 100644 index 000000000000..a1deb4121034 --- /dev/null +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/string/StringASCII.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.regex.tregex.string; + +import java.util.Arrays; + +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; + +public final class StringASCII implements AbstractString { + + @CompilationFinal(dimensions = 1) private final byte[] str; + + public StringASCII(byte[] str) { + this.str = str; + } + + @Override + public int encodedLength() { + return str.length; + } + + @Override + public Object content() { + return str; + } + + @Override + public String toString() { + return defaultToString(); + } + + @Override + public StringASCII substring(int start, int end) { + return new StringASCII(Arrays.copyOfRange(str, start, end)); + } + + @Override + public boolean regionMatches(int offset, AbstractString other, int ooffset, int encodedLength) { + byte[] o = ((StringASCII) other).str; + if (offset + encodedLength > str.length || ooffset + encodedLength > o.length) { + return false; + } + for (int i = 0; i < encodedLength; i++) { + if (str[offset + i] != o[ooffset + i]) { + return false; + } + } + return true; + } + + @Override + public AbstractStringIterator iterator() { + return new StringASCIIIterator(str); + } + + private static final class StringASCIIIterator extends AbstractStringIterator { + + private final byte[] str; + + private StringASCIIIterator(byte[] str) { + this.str = str; + } + + @Override + public boolean hasNext() { + return i < str.length; + } + + @Override + public int nextInt() { + return Byte.toUnsignedInt(str[i++]); + } + } +} diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/string/StringBufferASCII.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/string/StringBufferASCII.java new file mode 100644 index 000000000000..950806d27bcf --- /dev/null +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/string/StringBufferASCII.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.regex.tregex.string; + +import com.oracle.truffle.regex.tregex.buffer.ByteArrayBuffer; +import com.oracle.truffle.regex.tregex.string.Encodings.Encoding; + +public final class StringBufferASCII extends ByteArrayBuffer implements AbstractStringBuffer { + + public StringBufferASCII() { + this(16); + } + + public StringBufferASCII(int capacity) { + super(capacity); + } + + @Override + public Encoding getEncoding() { + return Encodings.ASCII; + } + + @Override + public void append(int codepoint) { + assert codepoint <= Encodings.ASCII.getMaxValue(); + add((byte) codepoint); + } + + @Override + public void appendOR(int c1, int c2) { + assert c1 <= Encodings.ASCII.getMaxValue(); + assert c2 <= Encodings.ASCII.getMaxValue(); + add((byte) (c1 | c2)); + } + + @Override + public void appendXOR(int c1, int c2) { + assert c1 <= Encodings.ASCII.getMaxValue(); + assert c2 <= Encodings.ASCII.getMaxValue(); + add((byte) (c1 ^ c2)); + } + + @Override + public StringASCII materialize() { + return new StringASCII(toArray()); + } +} diff --git a/regex/src/com.oracle.truffle.regex/tools/run_scripts.sh b/regex/src/com.oracle.truffle.regex/tools/run_scripts.sh index df4d0ec92b75..54ee2383d991 100755 --- a/regex/src/com.oracle.truffle.regex/tools/run_scripts.sh +++ b/regex/src/com.oracle.truffle.regex/tools/run_scripts.sh @@ -47,7 +47,7 @@ then exit 1 fi -UNICODE_VERSION=13.0.0 +UNICODE_VERSION=14.0.0 mkdir -p ./dat diff --git a/sdk/CHANGELOG.md b/sdk/CHANGELOG.md index 3d7ca70b21f8..7e9aed9588b2 100644 --- a/sdk/CHANGELOG.md +++ b/sdk/CHANGELOG.md @@ -2,6 +2,10 @@ This changelog summarizes major changes between GraalVM SDK versions. The main focus is on APIs exported by GraalVM SDK. +## Version 22.0.0 +* (GR-33657) Native Image API: Added `CEntryPoint#include` attribute which can be used to controll if the entry point should be automatically added to the shared library. +* (GR-33207) Native image language libraries: languages can now be deployed as native image libraries, facilitating native embedding scenarios. In this case, a native launcher loads the library dynamically. + ## Version 21.3.0 * Added the ability to share values between contexts. Please see `Context.Builder.allowValueSharing(boolean)` for further details. * (GR-20286) Polyglot API: Added support for scoped values in guest-to-host callbacks. [Scoped values](https://www.graalvm.org/reference-manual/embed-languages/#controlling-host-callback-parameter-scoping) are automatically released when the callback returns. They can be configured in `HostAccess`. diff --git a/sdk/ci.hocon b/sdk/ci.hocon deleted file mode 100644 index 48b28458ad75..000000000000 --- a/sdk/ci.hocon +++ /dev/null @@ -1,19 +0,0 @@ -sdkCommon: { - setup : [ - [cd, "./sdk"] - ] - timelimit : "30:00" -} - -sdkGate : ${sdkCommon} { - targets : [ gate ], - run : [ - ["mx", "gate"] - ] -} - -builds += [ - ${linux-amd64} ${oraclejdk8} ${sdkGate} ${eclipse} ${jdt} { name: "gate-sdk-linux-8" }, - ${linux-amd64} ${oraclejdk11} ${sdkGate} ${eclipse} { name: "gate-sdk-linux-oraclejdk-11" }, - ${darwin-amd64} ${oraclejdk8} ${sdkGate} { name: "gate-sdk-darwin-8" }, -] diff --git a/sdk/ci.jsonnet b/sdk/ci.jsonnet new file mode 100644 index 000000000000..fc621fc73fdb --- /dev/null +++ b/sdk/ci.jsonnet @@ -0,0 +1,22 @@ +{ + local common = import '../common.jsonnet', + + local sdk_gate = { + name: 'gate-sdk-oraclejdk' + self.jdk_version + '-' + self.os + '-' + self.arch, + setup: [ + ["cd", "./sdk"], + ], + run: [ + ["mx", "gate"] + ], + targets: ["gate"], + timelimit: "30:00", + }, + + builds: [ + common["linux-amd64"] + common.oraclejdk11 + sdk_gate + common.eclipse + common.jdt, + common["linux-amd64"] + common.oraclejdk17 + sdk_gate + common.eclipse + common.jdt, + common["darwin-amd64"] + common.oraclejdk11 + sdk_gate, + common["darwin-amd64"] + common.oraclejdk17 + sdk_gate, + ] +} diff --git a/sdk/mx.sdk/mx_sdk.py b/sdk/mx.sdk/mx_sdk.py index 4095538281ff..e8d94735611b 100644 --- a/sdk/mx.sdk/mx_sdk.py +++ b/sdk/mx.sdk/mx_sdk.py @@ -143,6 +143,7 @@ def mx_post_parse_cmd_line(args): LauncherConfig = mx_sdk_vm.LauncherConfig LanguageLauncherConfig = mx_sdk_vm.LanguageLauncherConfig LibraryConfig = mx_sdk_vm.LibraryConfig +LanguageLibraryConfig = mx_sdk_vm.LanguageLibraryConfig GraalVmComponent = mx_sdk_vm.GraalVmComponent GraalVmTruffleComponent = mx_sdk_vm.GraalVmTruffleComponent GraalVmLanguage = mx_sdk_vm.GraalVmLanguage @@ -157,8 +158,8 @@ def register_graalvm_component(component): return mx_sdk_vm.register_graalvm_component(component) -def graalvm_component_by_name(name): - return mx_sdk_vm.graalvm_component_by_name(name) +def graalvm_component_by_name(name, fatalIfMissing=True): + return mx_sdk_vm.graalvm_component_by_name(name, fatalIfMissing=fatalIfMissing) def graalvm_components(opt_limit_to_suite=False): diff --git a/sdk/mx.sdk/mx_sdk_vm.py b/sdk/mx.sdk/mx_sdk_vm.py index 9067f23c0f43..0b5df4036d1b 100644 --- a/sdk/mx.sdk/mx_sdk_vm.py +++ b/sdk/mx.sdk/mx_sdk_vm.py @@ -191,14 +191,28 @@ def __init__(self, destination, jar_distributions, main_class, build_args, langu class LibraryConfig(AbstractNativeImageConfig): - def __init__(self, destination, jar_distributions, build_args, jvm_library=False, use_modules=None, **kwargs): + def __init__(self, destination, jar_distributions, build_args, jvm_library=False, use_modules=None, home_finder=False, **kwargs): """ :param bool jvm_library """ - super(LibraryConfig, self).__init__(destination, jar_distributions, build_args, use_modules, **kwargs) + super(LibraryConfig, self).__init__(destination, jar_distributions, build_args, use_modules, home_finder=home_finder, **kwargs) self.jvm_library = jvm_library +class LanguageLibraryConfig(LibraryConfig): + def __init__(self, destination, jar_distributions, main_class, build_args, language, is_sdk_launcher=True, launchers=None, **kwargs): + """ + :param str language + :param str main_class + """ + super(LanguageLibraryConfig, self).__init__(destination, jar_distributions, build_args, home_finder=True, **kwargs) + self.is_sdk_launcher = is_sdk_launcher + self.main_class = main_class + self.language = language + self.default_symlinks = None + self.relative_home_paths = {} + self.launchers = [mx_subst.path_substitutions.substitute(l) for l in launchers] if launchers else [] + class GraalVmComponent(object): def __init__(self, suite, diff --git a/sdk/mx.sdk/mx_sdk_vm_impl.py b/sdk/mx.sdk/mx_sdk_vm_impl.py index bf0005e74595..46bc1db34e4c 100644 --- a/sdk/mx.sdk/mx_sdk_vm_impl.py +++ b/sdk/mx.sdk/mx_sdk_vm_impl.py @@ -59,6 +59,7 @@ import mx import mx_gate +import mx_native import mx_subst import mx_sdk import mx_sdk_vm @@ -341,6 +342,7 @@ def __init__(self, suite, name, deps, components, is_graalvm, exclLibs, platform stage1=False, **kw_args): # pylint: disable=super-init-not-called self.components = components or registered_graalvm_components(stage1) + self.stage1 = stage1 self.skip_archive = stage1 # Do not build *.tar archive for stage1 distributions layout = {} src_jdk_base = _src_jdk_base if add_jdk_base else '.' @@ -721,6 +723,11 @@ def _find_escaping_links(root_dir): # add `LibraryConfig.destination` and the generated header files to the layout _add(layout, _svm_library_dest, _source_type + ':' + _library_project_name, _component) _add(layout, _svm_library_home, _source_type + ':' + _library_project_name + '/*.h', _component) + if (not stage1 or _skip_libraries(_library_config)) and isinstance(_library_config, mx_sdk.LanguageLibraryConfig): + # add native launchers for language libraries + for _executable in _library_config.launchers: + _add(layout, join(_component_base, _executable), 'dependency:{}'.format(NativeLibraryLauncherProject.library_launcher_project_name(_library_config)), _component) + _add_link(_jdk_jre_bin, _component_base + _executable) _add_native_image_macro(_library_config, _component) graalvm_dists.update(_component.polyglot_lib_jar_dependencies) @@ -880,13 +887,19 @@ def build(self): class GraalVmLayoutDistribution(BaseGraalVmLayoutDistribution, LayoutSuper): # pylint: disable=R0901 def __init__(self, base_name, theLicense=None, stage1=False, components=None, **kw_args): self.base_name = base_name - name, base_dir, self.vm_config_name = _get_graalvm_configuration(base_name, components=components, stage1=stage1) + components_with_dependencies = [] if components is None else GraalVmLayoutDistribution._add_dependencies(components) + if components is not None: + for c in components: + if c.launcher_configs or c.library_configs: + mx.abort('Cannot define a GraalVM layout distribution with a forced list of components that includes launcher or library configs. ' + 'The corresponding projects refer to the global stage1 and final GraalVM distributions.') + name, base_dir, self.vm_config_name = _get_graalvm_configuration(base_name, components=components_with_dependencies, stage1=stage1) super(GraalVmLayoutDistribution, self).__init__( suite=_suite, name=name, deps=[], - components=components, + components=components_with_dependencies, is_graalvm=True, exclLibs=[], platformDependent=True, @@ -898,6 +911,17 @@ def __init__(self, base_name, theLicense=None, stage1=False, components=None, ** stage1=stage1, **kw_args) + @staticmethod + def _add_dependencies(components): + components_with_repetitions = components[:] + components_with_dependencies = [] + while components_with_repetitions: + component = components_with_repetitions.pop(0) + if component not in components_with_dependencies: + components_with_dependencies.append(component) + components_with_repetitions.extend(component.direct_dependencies()) + return components_with_dependencies + def extra_suite_revisions_data(self): base_jdk_info = _base_jdk_info() if self == get_final_graalvm_distribution() and base_jdk_info: @@ -958,6 +982,10 @@ def _get_graalvm_configuration(base_name, components=None, stage1=False): m = hashlib.sha1() for component in components_sorted_set: m.update(_encode(component)) + if _jlink_libraries(): + m.update(_encode("jlinked")) + else: + m.update(_encode("not-jlinked")) short_sha1_digest = m.hexdigest()[:10] # to keep paths short base_dir = '{base_name}_{hash}_java{jdk_version}'.format(base_name=base_name, hash=short_sha1_digest, jdk_version=_src_jdk_version) name = '{base_dir}{stage_suffix}'.format(base_dir=base_dir, stage_suffix='_stage1' if stage1 else '') @@ -1259,9 +1287,15 @@ def contents(self): else: raise mx.abort("Unsupported image config type: " + str(type(image_config))) - if isinstance(image_config, mx_sdk.LanguageLauncherConfig): + if isinstance(image_config, (mx_sdk.LanguageLauncherConfig, mx_sdk.LanguageLibraryConfig)): build_args += ['--language:' + image_config.language, '--tool:all'] + if isinstance(image_config, mx_sdk.LanguageLibraryConfig): + build_args += [ + '-Dorg.graalvm.launcher.class=' + image_config.main_class, + '-H:+EnableSignalAPI', + ] + source_type = 'skip' if isinstance(image_config, mx_sdk.LibraryConfig) and _skip_libraries(image_config) else 'dependency' graalvm_image_destination = graalvm_dist.find_single_source_location(source_type + ':' + project_name_f(image_config)) @@ -1271,13 +1305,12 @@ def contents(self): '-Dorg.graalvm.launcher.relative.home=' + relpath(graalvm_image_destination, graalvm_home), ] - if isinstance(image_config, mx_sdk.LauncherConfig): + if isinstance(image_config, (mx_sdk.LauncherConfig, mx_sdk.LanguageLibraryConfig)): if image_config.is_sdk_launcher: launcher_classpath = NativePropertiesBuildTask.get_launcher_classpath(graalvm_dist, graalvm_home, image_config, self.subject.component, exclude_implicit=True) - build_args += [ - '-H:-ParseRuntimeOptions', - '-Dorg.graalvm.launcher.classpath=' + os.pathsep.join(launcher_classpath), - ] + build_args += ['-Dorg.graalvm.launcher.classpath=' + os.pathsep.join(launcher_classpath)] + if isinstance(image_config, mx_sdk.LauncherConfig): + build_args += ['-H:-ParseRuntimeOptions'] build_args += [ '--install-exit-handlers', @@ -2149,8 +2182,9 @@ def _gen_gu_manifest(components, formatter, bundled=False): dependencies = sorted(dependencies) if dependencies: manifest["Require-Bundle"] = ','.join(("org.graalvm." + d for d in dependencies)) - if isinstance(main_component, mx_sdk.GraalVmLanguage): - _wd_base = join('jre', 'languages') if _src_jdk_version < 9 else 'languages' + if isinstance(main_component, (mx_sdk.GraalVmLanguage, mx_sdk.GraalVmTool)): + _component_type_base = 'languages' if isinstance(main_component, mx_sdk.GraalVmLanguage) else 'tools' + _wd_base = join('jre', _component_type_base) if _src_jdk_version < 9 else _component_type_base manifest["x-GraalVM-Working-Directories"] = join(_wd_base, main_component.dir_name) post_install_msg = None @@ -2260,10 +2294,6 @@ def create_archive(path, **_kw_args): other_involved_components += [c for c in registered_graalvm_components(stage1=True) if c.short_name in ('svm', 'svmee')] name = '{}_INSTALLABLE'.format(component.installable_id.replace('-', '_').upper()) - if other_involved_components: - for launcher_config in launcher_configs: - if _force_bash_launchers(launcher_config): - name += '_B' + basename(launcher_config.destination).upper() for library_config in library_configs: if _skip_libraries(library_config): name += '_S' + basename(library_config.destination).upper() @@ -2541,6 +2571,65 @@ def _get_native_image_configs(component, config_type): def _libpolyglot_macro_dist_name(component): return component.short_name + "_libpolyglot_macro" +class NativeLibraryLauncherProject(mx_native.DefaultNativeProject): + def __init__(self, component, language_library_config): + _dir = join(_suite.dir, "src", "org.graalvm.launcher.native") + self.language_library_config = language_library_config + self.component = component + self.jvm_launcher = _skip_libraries(self.language_library_config) or not _get_svm_support().is_supported() + _dependencies = [] if self.jvm_launcher else [GraalVmNativeImage.project_name(self.language_library_config)] + super(NativeLibraryLauncherProject, self).__init__(_suite, NativeLibraryLauncherProject.library_launcher_project_name(self.language_library_config), 'src', [], _dependencies, None, _dir, 'executable', deliverable=self.language_library_config.language, use_jdk_headers=True) + + @staticmethod + def library_launcher_project_name(language_library_config): + return "org.graalvm.launcher.native." + language_library_config.language + + @property + def cflags(self): + _dist = get_final_graalvm_distribution() + _exe_path = _dist.find_single_source_location('dependency:' + NativeLibraryLauncherProject.library_launcher_project_name(self.language_library_config)) + _dynamic_cflags = [ + '-DCP_SEP=' + os.pathsep, + '-DDIR_SEP=' + ('\\\\' if mx.is_windows() else '/'), + ] + if self.jvm_launcher: + _graalvm_home = _get_graalvm_archive_path("") + _cp = NativePropertiesBuildTask.get_launcher_classpath(_dist, _graalvm_home, self.language_library_config, self.component, exclude_implicit=True) + _cp = [join(_dist.path_substitutions.substitute(''), x) for x in _cp] + # path from langauge launcher to jars + _cp = [relpath(x, start=dirname(_exe_path)) for x in _cp] + if mx.is_windows(): + _libjvm_path = join(_dist.path_substitutions.substitute(''), 'bin', 'server', 'jvm.dll') + _libjvm_path = relpath(_libjvm_path, start=dirname(_exe_path)).replace('\\', '\\\\') + _cp = [x.replace('\\', '\\\\') for x in _cp] + else: + if _src_jdk_version < 9 and mx.is_linux(): + _libjvm_path = join(_dist.path_substitutions.substitute(''), 'lib', mx.get_arch(), 'server', mx.add_lib_suffix("libjvm")) + else: + _libjvm_path = join(_dist.path_substitutions.substitute(''), 'lib', 'server', mx.add_lib_suffix("libjvm")) + _libjvm_path = relpath(_libjvm_path, start=dirname(_exe_path)) + _dynamic_cflags += [ + '-DJVM', + '-DLAUNCHER_CLASS=' + self.language_library_config.main_class, + '-DLAUNCHER_CLASSPATH="{\\"' + '\\", \\"'.join(_cp) + '\\"}"', + '-DLIBLANG_RELPATH=' + _libjvm_path, + ] + else: + _lib_path = _dist.find_single_source_location('dependency:' + GraalVmLibrary.project_name(self.language_library_config)) + # path from language launcher to library + _liblang_relpath = relpath(_lib_path, start=dirname(_exe_path)) + _dynamic_cflags += [ + '-DLIBLANG_RELPATH=' + (_liblang_relpath.replace('\\', '\\\\') if mx.is_windows() else _liblang_relpath) + ] + return super(NativeLibraryLauncherProject, self).cflags + _dynamic_cflags + + @property + def ldlibs(self): + _dynamic_ldlibs = [] + if not mx.is_windows(): + _dynamic_ldlibs += ['-ldl'] + return super(NativeLibraryLauncherProject, self).ldlibs + _dynamic_ldlibs + def has_vm_suite(): global _vm_suite if _vm_suite == 'uninitialized': @@ -2587,12 +2676,15 @@ def mx_register_dynamic_suite_constituents(register_project, register_distributi needs_stage1 = True if with_svm: register_project(GraalVmNativeProperties(component, launcher_config)) - if with_svm: - for library_config in _get_library_configs(component): + for library_config in _get_library_configs(component): + if with_svm: register_project(GraalVmLibrary(component, GraalVmNativeImage.project_name(library_config), [], library_config)) assert with_svm register_project(GraalVmNativeProperties(component, library_config)) needs_stage1 = True # library configs need a stage1 even when they are skipped + if isinstance(library_config, mx_sdk.LanguageLibraryConfig): + launcher_project = NativeLibraryLauncherProject(component, library_config) + register_project(launcher_project) if component.installable and not _disable_installable(component): installables.setdefault(component.installable_id, []).append(component) if libpolyglot_component is not None and GraalVmLibPolyglotNativeProperties.needs_lib_polyglot_native_properties(component): @@ -2793,6 +2885,43 @@ def print_standalone_home(args): print(standalone_home(args.comp_dir_name)) +def _infer_env(graalvm_dist): + dynamicImports = set() + components = [] + foundLibpoly = False + for component in registered_graalvm_components(): + if component.short_name == 'libpoly': + foundLibpoly = True + else: + components.append(component.short_name) + suite = component.suite + if suite.dir == suite.vc_dir: + dynamicImports.add(os.path.basename(suite.dir)) + else: + dynamicImports.add("/" + os.path.basename(suite.dir)) + excludeComponents = [] if foundLibpoly else ['libpoly'] # 'libpoly' is special, we need to exclude it instead of including + + nativeImages = [] + for p in _suite.projects: + if isinstance(p, GraalVmLauncher) and p.get_containing_graalvm() == graalvm_dist: + if p.is_native(): + nativeImages.append(p.native_image_name) + elif not graalvm_dist.stage1 and isinstance(p, GraalVmLibrary): + if not p.is_skipped(): + library_name = remove_lib_prefix_suffix(p.native_image_name, require_suffix_prefix=False) + nativeImages.append('lib:' + library_name) + if not nativeImages: + nativeImages = ['false'] + + disableInstallables = _disabled_installables() + if disableInstallables is None: + disableInstallables = [] + elif isinstance(disableInstallables, bool): + disableInstallables = [str(disableInstallables)] + + return sorted(list(dynamicImports)), sorted(components), sorted(excludeComponents), sorted(nativeImages), sorted(disableInstallables), _no_licenses() + + def graalvm_enter(args): """enter a subshell for developing with a particular GraalVM config""" env = os.environ.copy() @@ -2848,38 +2977,17 @@ def graalvm_enter(args): return graalvm_dist = get_final_graalvm_distribution() - - components = [] - dynamicImports = set() - foundLibpoly = False - for component in registered_graalvm_components(): - if component.short_name == 'libpoly': - foundLibpoly = True # 'libpoly' is special, we need to exclude it instead of including - else: - components.append(component.short_name) - suite = component.suite - if suite.dir == suite.vc_dir: - dynamicImports.add(os.path.basename(suite.dir)) - else: - dynamicImports.add("/" + os.path.basename(suite.dir)) - - nativeImages = [] - for p in _suite.projects: - if isinstance(p, GraalVmLauncher) and p.get_containing_graalvm() == graalvm_dist: - if p.is_native(): - nativeImages.append(p.native_image_name) - elif isinstance(p, GraalVmLibrary): - if not p.is_skipped(): - library_name = remove_lib_prefix_suffix(p.native_image_name, require_suffix_prefix=False) - nativeImages.append('lib:' + library_name) + dynamicImports, components, exclude_components, nativeImages, disableInstallables, noLicenses = _infer_env(graalvm_dist) env['GRAALVM_HOME'] = graalvm_home() env['DYNAMIC_IMPORTS'] = ','.join(dynamicImports) env['COMPONENTS'] = ','.join(components) env['NATIVE_IMAGES'] = ','.join(nativeImages) - if not foundLibpoly: - env['EXCLUDE_COMPONENTS'] = 'libpoly' + env['EXCLUDE_COMPONENTS'] = ','.join(exclude_components) + env['DISABLE_INSTALLABLES'] = ','.join(disableInstallables) + if noLicenses: + env['NO_LICENSES'] = 'true' # Disable loading of the global ~/.mx/env file in the subshell. The contents of this file are already in the current # environment. Parsing the ~/.mx/env file again would lead to confusing results, especially if it contains settings @@ -2890,61 +2998,83 @@ def graalvm_enter(args): mx.run(args.cmd, env=env) -def graalvm_show(args): - """print the GraalVM config""" +def graalvm_show(args, forced_graalvm_dist=None): + """print the GraalVM config + + :param forced_graalvm_dist: the GraalVM distribution whose config is printed. If None, then the + config of the global stage1 or final GraalVM distribution is printed. + """ parser = ArgumentParser(prog='mx graalvm-show', description='Print the GraalVM config') parser.add_argument('--stage1', action='store_true', help='show the components for stage1') + parser.add_argument('--print-env', action='store_true', help='print the contents of an env file that reproduces the current GraalVM config') args = parser.parse_args(args) - graalvm_dist = get_stage1_graalvm_distribution() if args.stage1 else get_final_graalvm_distribution() + graalvm_dist = forced_graalvm_dist or (get_stage1_graalvm_distribution() if args.stage1 else get_final_graalvm_distribution()) print("GraalVM distribution: {}".format(graalvm_dist)) print("Version: {}".format(_suite.release_version())) print("Config name: {}".format(graalvm_dist.vm_config_name)) print("Components:") - for component in registered_graalvm_components(stage1=args.stage1): + for component in graalvm_dist.components: print(" - {} ('{}', /{})".format(component.name, component.short_name, component.dir_name)) - launchers = [p for p in _suite.projects if isinstance(p, GraalVmLauncher) and p.get_containing_graalvm() == graalvm_dist] - if launchers: - print("Launchers:") - for launcher in launchers: - suffix = '' - profile_cnt = len(_image_profile(GraalVmNativeProperties.canonical_image_name(launcher.native_image_config))) - if profile_cnt > 0: - suffix += " ({} pgo profile file{})".format(profile_cnt, 's' if profile_cnt > 1 else '') - print(" - {} ({}){}".format(launcher.native_image_name, "native" if launcher.is_native() else "bash", suffix)) - else: - print("No launcher") - - libraries = [p for p in _suite.projects if isinstance(p, GraalVmLibrary)] - if libraries and not args.stage1: - print("Libraries:") - for library in libraries: - suffix = '' - if library.is_skipped(): - suffix += " (skipped)" - profile_cnt = len(_image_profile(GraalVmNativeProperties.canonical_image_name(library.native_image_config))) - if profile_cnt > 0: - suffix += " ({} pgo profile file{})".format(profile_cnt, 's' if profile_cnt > 1 else '') - print(" - {}{}".format(library.native_image_name, suffix)) - else: - print("No library") + if forced_graalvm_dist is None: + # Custom GraalVM distributions with a forced component list do not yet support launchers and libraries. + # No installable or standalone is derived from them. + launchers = [p for p in _suite.projects if isinstance(p, GraalVmLauncher) and p.get_containing_graalvm() == graalvm_dist] + if launchers: + print("Launchers:") + for launcher in launchers: + suffix = '' + profile_cnt = len(_image_profile(GraalVmNativeProperties.canonical_image_name(launcher.native_image_config))) + if profile_cnt > 0: + suffix += " ({} pgo profile file{})".format(profile_cnt, 's' if profile_cnt > 1 else '') + print(" - {} ({}){}".format(launcher.native_image_name, "native" if launcher.is_native() else "bash", suffix)) + else: + print("No launcher") + + libraries = [p for p in _suite.projects if isinstance(p, GraalVmLibrary)] + if libraries and not args.stage1: + print("Libraries:") + for library in libraries: + suffix = '' + if library.is_skipped(): + suffix += " (skipped)" + profile_cnt = len(_image_profile(GraalVmNativeProperties.canonical_image_name(library.native_image_config))) + if profile_cnt > 0: + suffix += " ({} pgo profile file{})".format(profile_cnt, 's' if profile_cnt > 1 else '') + print(" - {}{}".format(library.native_image_name, suffix)) + else: + print("No library") - installables = _get_dists(GraalVmInstallableComponent) - if installables and not args.stage1: - print("Installables:") - for i in installables: - print(" - {}".format(i)) - else: - print("No installable") + installables = _get_dists(GraalVmInstallableComponent) + if installables and not args.stage1: + print("Installables:") + for i in installables: + print(" - {}".format(i)) + else: + print("No installable") - standalones = _get_dists(GraalVmStandaloneComponent) - if standalones and not args.stage1: - print("Standalones:") - for s in standalones: - print(" - {}".format(s)) - else: - print("No standalone") + standalones = _get_dists(GraalVmStandaloneComponent) + if standalones and not args.stage1: + print("Standalones:") + for s in standalones: + print(" - {}".format(s)) + else: + print("No standalone") + + if args.print_env: + def _print_env(name, val): + if val: + print(name + '=' + ','.join(val)) + print('Inferred env file:') + dynamic_imports, components, exclude_components, native_images, disable_installables, no_licenses = _infer_env(graalvm_dist) + _print_env('DYNAMIC_IMPORTS', dynamic_imports) + _print_env('COMPONENTS', components) + _print_env('EXCLUDE_COMPONENTS', exclude_components) + _print_env('NATIVE_IMAGES', native_images) + _print_env('DISABLE_INSTALLABLES', disable_installables) + if no_licenses: + print('NO_LICENSES=true') def _get_dists(dist_class): @@ -3103,16 +3233,22 @@ def _debug_images(): def _components_include_list(): - included = _parse_cmd_arg('components', parse_bool=False, default_value=None) + included = _parse_cmd_arg('components', parse_bool=True, default_value=None) if included is None: return None + if isinstance(included, bool): + return mx_sdk_vm.graalvm_components() if included else [] components = [] for name in included: if name.startswith('suite:'): suite_name = name[len('suite:'):] components.extend([c for c in mx_sdk_vm.graalvm_components() if c.suite.name == suite_name]) else: - components.append(mx_sdk.graalvm_component_by_name(name)) + component = mx_sdk.graalvm_component_by_name(name, False) + if component: + components.append(component) + else: + mx.warn("The component inclusion list ('--components' or '$COMPONENTS') includes an unknown component: '{}'".format(name)) return components @@ -3213,9 +3349,13 @@ def _skip_libraries(library): return library_name in skipped +def _disabled_installables(): + return _parse_cmd_arg('disable_installables', default_value=str(not has_vm_suite())) + + def _disable_installable(component): """ :type component: str | mx_sdk.GraalVmComponent """ - disabled = _parse_cmd_arg('disable_installables', default_value=str(not has_vm_suite())) + disabled = _disabled_installables() if isinstance(disabled, bool): return disabled else: diff --git a/sdk/mx.sdk/suite.py b/sdk/mx.sdk/suite.py index e437c7f85251..15bee000c6b5 100644 --- a/sdk/mx.sdk/suite.py +++ b/sdk/mx.sdk/suite.py @@ -41,7 +41,7 @@ suite = { "mxversion" : "5.309.1", "name" : "sdk", - "version" : "21.3.0", + "version" : "22.0.0", "release" : False, "sourceinprojectwhitelist" : [], "url" : "https://github.com/oracle/graal", diff --git a/sdk/src/org.graalvm.collections/snapshot.sigtest b/sdk/src/org.graalvm.collections/snapshot.sigtest index 3c22fbe84336..6067a5fb781c 100644 --- a/sdk/src/org.graalvm.collections/snapshot.sigtest +++ b/sdk/src/org.graalvm.collections/snapshot.sigtest @@ -34,6 +34,7 @@ meth public static <%0 extends java.lang.Object, %1 extends java.lang.Object> or meth public static <%0 extends java.lang.Object, %1 extends java.lang.Object> org.graalvm.collections.EconomicMap<{%%0},{%%1}> create(org.graalvm.collections.Equivalence,org.graalvm.collections.UnmodifiableEconomicMap<{%%0},{%%1}>) meth public static <%0 extends java.lang.Object, %1 extends java.lang.Object> org.graalvm.collections.EconomicMap<{%%0},{%%1}> create(org.graalvm.collections.UnmodifiableEconomicMap<{%%0},{%%1}>) meth public static <%0 extends java.lang.Object, %1 extends java.lang.Object> org.graalvm.collections.EconomicMap<{%%0},{%%1}> wrapMap(java.util.Map<{%%0},{%%1}>) +meth public static <%0 extends java.lang.Object, %1 extends java.lang.Object> org.graalvm.collections.MapCursor<{%%0},{%%1}> emptyCursor() meth public void putAll(org.graalvm.collections.EconomicMap<{org.graalvm.collections.EconomicMap%0},{org.graalvm.collections.EconomicMap%1}>) meth public void putAll(org.graalvm.collections.UnmodifiableEconomicMap) meth public {org.graalvm.collections.EconomicMap%1} putIfAbsent({org.graalvm.collections.EconomicMap%0},{org.graalvm.collections.EconomicMap%1}) diff --git a/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMap.java b/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMap.java index 2f4290aa395e..baac845ede4a 100644 --- a/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMap.java +++ b/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMap.java @@ -230,4 +230,32 @@ static EconomicMap create(Equivalence strategy, int initialCapacity static EconomicMap wrapMap(Map map) { return new EconomicMapWrap<>(map); } + + /** + * Return an empty {@link MapCursor}. + * + * @since 22.0 + */ + static MapCursor emptyCursor() { + return new MapCursor() { + @Override + public void remove() { + } + + @Override + public boolean advance() { + return false; + } + + @Override + public K getKey() { + return null; + } + + @Override + public V getValue() { + return null; + } + }; + } } diff --git a/sdk/src/org.graalvm.launcher.native/src/launcher.cc b/sdk/src/org.graalvm.launcher.native/src/launcher.cc new file mode 100644 index 000000000000..f9fd5cc9b4ce --- /dev/null +++ b/sdk/src/org.graalvm.launcher.native/src/launcher.cc @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#define QUOTE(name) #name +#define STR(macro) QUOTE(macro) + +#ifdef JVM + #ifndef LAUNCHER_CLASS + #error launcher class undefined + #endif + #define LAUNCHER_CLASS_STR STR(LAUNCHER_CLASS) + #ifndef LAUNCHER_CLASSPATH + #error launcher classpath undefined + #endif +#endif + +#ifndef LIBLANG_RELPATH + #error path to native library undefined +#endif + +#ifndef DIR_SEP + #error directory separator undefined +#endif + +#ifndef CP_SEP + #error class path separator undefined +#endif + +#define LIBLANG_RELPATH_STR STR(LIBLANG_RELPATH) +#define DIR_SEP_STR STR(DIR_SEP) +#define CP_SEP_STR STR(CP_SEP) + +#if defined (__linux__) + #include + #include + #include + #include +#elif defined (__APPLE__) + #include + #include + #include + #include + #include +#elif defined (_WIN32) + #include + #include + #include +#else + #error platform not supported or undefined +#endif + +typedef jint(*CreateJVM)(JavaVM **, void **, void *); + +char *exe_directory() { + #if defined (__linux__) + return dirname(realpath("/proc/self/exe", NULL)); + #elif defined (__APPLE__) + char path[PATH_MAX]; + uint32_t path_len = PATH_MAX; + _NSGetExecutablePath(path, &path_len); + return dirname(realpath(path, NULL)); + #elif defined (_WIN32) + char *path = (char *)malloc(_MAX_PATH); + GetModuleFileNameA(NULL, path, _MAX_PATH); + // get the directory part + char drive[_MAX_DRIVE]; + char dir[_MAX_DIR]; + _splitpath_s(path, drive, _MAX_DRIVE, dir, _MAX_DIR, NULL, 0, NULL, 0); + _makepath_s(path, _MAX_PATH, drive, dir, NULL, NULL); + return path; + #endif +} + +CreateJVM loadliblang(char *exe_dir) { + int size = strlen(exe_dir) + sizeof(DIR_SEP_STR) + sizeof(LIBLANG_RELPATH_STR) + 1; + char *liblang_path = (char*)malloc(size); + strcpy(liblang_path, exe_dir); + strcat(liblang_path, DIR_SEP_STR); + strcat(liblang_path, LIBLANG_RELPATH_STR); +#if defined (__linux__) || defined (__APPLE__) + void* jvm_handle = dlopen(liblang_path, RTLD_NOW); + if (jvm_handle != NULL) { + return (CreateJVM) dlsym(jvm_handle, "JNI_CreateJavaVM"); + } +#else + HMODULE jvm_handle = LoadLibraryA(liblang_path); + if (jvm_handle != NULL) { + return (CreateJVM) GetProcAddress(jvm_handle, "JNI_CreateJavaVM"); + } +#endif + return NULL; +} + +int main(int argc, char **argv) { + char *exe_dir = exe_directory(); + CreateJVM createJVM = loadliblang(exe_dir); + if (!createJVM) { + fprintf(stderr, "Could not load language library.\n"); + return -1; + } + JavaVM *jvm; + JNIEnv *env; + JavaVMInitArgs vm_args; + JavaVMOption options[4]; + #ifdef JVM + const char *cp_entries[] = LAUNCHER_CLASSPATH; + int cp_cnt = sizeof(cp_entries) / sizeof(*cp_entries); + int size = (strlen(exe_dir) + sizeof(DIR_SEP_STR)) * cp_cnt + sizeof(CP_SEP_STR) * (cp_cnt-1) + 1; + for (int i = 0; i < cp_cnt; i++) { + size += strlen(cp_entries[i]); + } + const char cp_property[] = "-Djava.class.path="; + size += sizeof(cp_property); + char *cp = (char *)malloc(size); + strcpy(cp, cp_property); + for (int i = 0; i < cp_cnt; i++) { + strcat(cp, exe_dir); + strcat(cp, DIR_SEP_STR); + strcat(cp, cp_entries[i]); + if (i < cp_cnt-1) { + strcat(cp, CP_SEP_STR); + } + } + options[0].optionString = cp; + options[1].optionString = "-Dorg.graalvm.launcher.class=" LAUNCHER_CLASS_STR; + vm_args.nOptions = 2; + #else + vm_args.nOptions = 0; + #endif + vm_args.version = JNI_VERSION_1_8; + vm_args.options = options; + vm_args.ignoreUnrecognized = false; + + int res = createJVM(&jvm, (void**)&env, &vm_args); + if (res != JNI_OK) { + fprintf(stderr, "Creation of the JVM failed.\n"); + return -1; + } + jclass byteArrayClass = env->FindClass("[B"); + if (byteArrayClass == NULL) { + fprintf(stderr, "Byte array class not found.\n"); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + } + return -1; + } + jclass launcherClass = env->FindClass("org/graalvm/launcher/AbstractLanguageLauncher"); + if (launcherClass == NULL) { + fprintf(stderr, "Launcher class not found.\n"); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + } + return -1; + } + jmethodID mid = env->GetStaticMethodID(launcherClass, "runLauncher", "([[BIJ)V"); + if (mid == NULL) { + fprintf(stderr, "Launcher entry point not found.\n"); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + } + return -1; + } + + // create args string array + long argv_native = (long)argv; + int argc_native = argc; + argv++; + argc--; + + jobjectArray args = env->NewObjectArray(argc, byteArrayClass, NULL); + for (int i = 0; i < argc; i++) { + int arraySize = strlen(argv[i]); + jbyteArray arg = env->NewByteArray(arraySize); + env->SetByteArrayRegion(arg, 0, arraySize, (jbyte *)(argv[i])); + if (env->ExceptionCheck()) { + fprintf(stderr, "Error in SetByteArrayRegion:\n"); + env->ExceptionDescribe(); + return -1; + } + env->SetObjectArrayElement(args, i, arg); + if (env->ExceptionCheck()) { + fprintf(stderr, "Error in SetObjectArrayElement:\n"); + env->ExceptionDescribe(); + return -1; + } + } + + // invoke launcher entry point + env->CallStaticVoidMethod(launcherClass, mid, args, argc_native, argv_native); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return -1; + } + return 0; +} diff --git a/sdk/src/org.graalvm.launcher/src/META-INF/native-image/org.graalvm.launcher/launcher.jniconfig b/sdk/src/org.graalvm.launcher/src/META-INF/native-image/org.graalvm.launcher/launcher.jniconfig new file mode 100644 index 000000000000..3a35a5d84541 --- /dev/null +++ b/sdk/src/org.graalvm.launcher/src/META-INF/native-image/org.graalvm.launcher/launcher.jniconfig @@ -0,0 +1,8 @@ +[ + { + "name": "org.graalvm.launcher.AbstractLanguageLauncher", + "methods": [ + { "name": "runLauncher" } + ] + } +] diff --git a/sdk/src/org.graalvm.launcher/src/META-INF/native-image/org.graalvm.launcher/native-image.properties b/sdk/src/org.graalvm.launcher/src/META-INF/native-image/org.graalvm.launcher/native-image.properties index c5657e153d52..f2f92c7b5c9e 100644 --- a/sdk/src/org.graalvm.launcher/src/META-INF/native-image/org.graalvm.launcher/native-image.properties +++ b/sdk/src/org.graalvm.launcher/src/META-INF/native-image/org.graalvm.launcher/native-image.properties @@ -1 +1,2 @@ -Args = --features=com.oracle.svm.thirdparty.jline.JLine3Feature +Args = --features=com.oracle.svm.thirdparty.jline.JLine3Feature \ + -H:JNIConfigurationResources=${.}/launcher.jniconfig \ No newline at end of file diff --git a/sdk/src/org.graalvm.launcher/src/org/graalvm/launcher/AbstractLanguageLauncher.java b/sdk/src/org.graalvm.launcher/src/org/graalvm/launcher/AbstractLanguageLauncher.java index c5c12f2ed490..20c3350846a0 100644 --- a/sdk/src/org.graalvm.launcher/src/org/graalvm/launcher/AbstractLanguageLauncher.java +++ b/sdk/src/org.graalvm.launcher/src/org/graalvm/launcher/AbstractLanguageLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -40,6 +40,7 @@ */ package org.graalvm.launcher; +import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -47,6 +48,7 @@ import java.util.List; import java.util.Map; +import org.graalvm.nativeimage.RuntimeOptions; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Engine; import org.graalvm.polyglot.Language; @@ -54,6 +56,38 @@ public abstract class AbstractLanguageLauncher extends LanguageLauncherBase { + private static final Constructor LAUNCHER_CTOR; + private int nativeArgc; + private long nativeArgv; + + static { + LAUNCHER_CTOR = getLauncherCtor(); + } + + /** + * Looks up the launcher constructor based on the launcher class passed in via the + * org.graalvm.launcher.class system property. + * + * @return launcher constructor, if found. + */ + @SuppressWarnings("unchecked") + private static Constructor getLauncherCtor() { + String launcherClassName = System.getProperty("org.graalvm.launcher.class"); + Constructor launcherCtor = null; + if (launcherClassName != null) { + try { + Class launcherClass = (Class) Class.forName(launcherClassName); + if (!AbstractLanguageLauncher.class.isAssignableFrom(launcherClass)) { + throw new Exception("Launcher does not implement " + AbstractLanguageLauncher.class.getName()); + } + launcherCtor = launcherClass.getConstructor(); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + return launcherCtor; + } + /** * This starts the launcher. it should be called from the main method: * @@ -81,6 +115,54 @@ protected final void launch(String[] args) { } } + /** + * Entry point for invoking the launcher via JNI. Relies on a launcher constructor to be set via + * the org.graalvm.launcher.class system property. + * + * @param args the command line arguments as an encoding-agnostic byte array + * @param argc the number of native command line arguments + * @param argv pointer to argv + * @throws Exception if no launcher constructor has been set. + */ + public static void runLauncher(byte[][] args, int argc, long argv) throws Exception { + if (isAOT()) { + // enable signal handling for the launcher + RuntimeOptions.set("EnableSignalHandling", true); + } + + if (LAUNCHER_CTOR == null) { + throw new Exception("Launcher constructor has not been set."); + } + + String[] arguments = new String[args.length]; + for (int i = 0; i < args.length; i++) { + arguments[i] = new String(args[i]); + } + + AbstractLanguageLauncher launcher = LAUNCHER_CTOR.newInstance(); + launcher.nativeArgc = argc; + launcher.nativeArgv = argv; + launcher.launch(arguments); + } + + /** + * The native argument count as passed to the main method of the native launcher. + * + * @return native argument count, including the program name + */ + protected int getNativeArgc() { + return nativeArgc; + } + + /** + * The native argument values as passed to the main method of the native launcher. + * + * @return pointer to the native argument values, including the program name + */ + protected long getNativeArgv() { + return nativeArgv; + } + protected static final boolean IS_LIBPOLYGLOT = Boolean.getBoolean("graalvm.libpolyglot"); final void launch(List args, Map defaultOptions, boolean doNativeSetup) { diff --git a/sdk/src/org.graalvm.launcher/src/org/graalvm/launcher/Launcher.java b/sdk/src/org.graalvm.launcher/src/org/graalvm/launcher/Launcher.java index 8df6e4e1c20b..1cd0b502973a 100644 --- a/sdk/src/org.graalvm.launcher/src/org/graalvm/launcher/Launcher.java +++ b/sdk/src/org.graalvm.launcher/src/org/graalvm/launcher/Launcher.java @@ -973,9 +973,12 @@ private static String wrap(String s) { private void printOption(String option, String description, int indentStart, int optionWidth) { String indent = spaces(indentStart); - String desc = wrap(description != null ? description : ""); + String desc = description != null ? description : ""; String nl = System.lineSeparator(); String[] descLines = desc.split(nl); + for (int i = 0; i < descLines.length; i++) { + descLines[i] = wrap(descLines[i]); + } if (option.length() >= optionWidth && description != null) { out.println(indent + option + nl + indent + spaces(optionWidth) + descLines[0]); } else { @@ -1620,41 +1623,47 @@ protected static OutputStream newLogStream(Path path) throws IOException { Path usedPath = path; Path fileNamePath = path.getFileName(); String fileName = fileNamePath == null ? "" : fileNamePath.toString(); - Path lockFile = null; - FileChannel lockFileChannel = null; - for (int unique = 0;; unique++) { - StringBuilder lockFileNameBuilder = new StringBuilder(fileName); - if (unique > 0) { - lockFileNameBuilder.append(unique); - usedPath = path.resolveSibling(lockFileNameBuilder.toString()); - } - lockFileNameBuilder.append(".lck"); - lockFile = path.resolveSibling(lockFileNameBuilder.toString()); - Pair openResult = openChannel(lockFile); - if (openResult != null) { - lockFileChannel = openResult.getLeft(); - if (lock(lockFileChannel, openResult.getRight())) { - break; - } else { - // Close and try next name - lockFileChannel.close(); + OutputStream outputStream; + if (Files.exists(path) && !Files.isRegularFile(path)) { + // Don't try to lock device or named pipe. + outputStream = new BufferedOutputStream(Files.newOutputStream(usedPath, WRITE, CREATE, APPEND)); + } else { + Path lockFile = null; + FileChannel lockFileChannel = null; + for (int unique = 0;; unique++) { + StringBuilder lockFileNameBuilder = new StringBuilder(fileName); + if (unique > 0) { + lockFileNameBuilder.append(unique); + usedPath = path.resolveSibling(lockFileNameBuilder.toString()); + } + lockFileNameBuilder.append(".lck"); + lockFile = path.resolveSibling(lockFileNameBuilder.toString()); + Pair openResult = openChannel(lockFile); + if (openResult != null) { + lockFileChannel = openResult.getLeft(); + if (lock(lockFileChannel, openResult.getRight())) { + break; + } else { + // Close and try next name + lockFileChannel.close(); + } } } - } - assert lockFile != null && lockFileChannel != null; - boolean success = false; - try { - OutputStream stream = new LockableOutputStream( - new BufferedOutputStream(Files.newOutputStream(usedPath, WRITE, CREATE, APPEND)), - lockFile, - lockFileChannel); - success = true; - return stream; - } finally { - if (!success) { - LockableOutputStream.unlock(lockFile, lockFileChannel); + assert lockFile != null && lockFileChannel != null; + boolean success = false; + try { + outputStream = new LockableOutputStream( + new BufferedOutputStream(Files.newOutputStream(usedPath, WRITE, CREATE, APPEND)), + lockFile, + lockFileChannel); + success = true; + } finally { + if (!success) { + LockableOutputStream.unlock(lockFile, lockFileChannel); + } } } + return outputStream; } private static Pair openChannel(Path path) throws IOException { diff --git a/sdk/src/org.graalvm.launcher/src/org/graalvm/launcher/MultiLanguageShell.java b/sdk/src/org.graalvm.launcher/src/org/graalvm/launcher/MultiLanguageShell.java index 4923727ecbf1..1a857ac824f3 100644 --- a/sdk/src/org.graalvm.launcher/src/org/graalvm/launcher/MultiLanguageShell.java +++ b/sdk/src/org.graalvm.launcher/src/org/graalvm/launcher/MultiLanguageShell.java @@ -223,7 +223,7 @@ private boolean handleBuiltins() { private void printHeader() { println("GraalVM MultiLanguage Shell " + context.getEngine().getVersion()); - println("Copyright (c) 2013-2020, Oracle and/or its affiliates"); + println("Copyright (c) 2013-2021, Oracle and/or its affiliates"); for (Language language : languages) { println(" " + language.getName() + " version " + language.getVersion()); } diff --git a/sdk/src/org.graalvm.nativeimage/snapshot.sigtest b/sdk/src/org.graalvm.nativeimage/snapshot.sigtest index df2964afe9ff..5dc7f0afe64f 100644 --- a/sdk/src/org.graalvm.nativeimage/snapshot.sigtest +++ b/sdk/src/org.graalvm.nativeimage/snapshot.sigtest @@ -114,6 +114,10 @@ CLSS public abstract interface !annotation java.lang.annotation.Target intf java.lang.annotation.Annotation meth public abstract java.lang.annotation.ElementType[] value() +CLSS public abstract interface java.util.function.BooleanSupplier + anno 0 java.lang.FunctionalInterface() +meth public abstract boolean getAsBoolean() + CLSS public final org.graalvm.nativeimage.CurrentIsolate meth public static org.graalvm.nativeimage.Isolate getIsolate() meth public static org.graalvm.nativeimage.IsolateThread getCurrentThread() @@ -457,13 +461,22 @@ CLSS public abstract interface !annotation org.graalvm.nativeimage.c.function.CE innr public abstract interface static !annotation IsolateContext innr public abstract interface static !annotation IsolateThreadContext innr public final static !enum Builtin +innr public final static AlwaysIncluded innr public final static FatalExceptionHandler +innr public final static NotIncludedAutomatically intf java.lang.annotation.Annotation +meth public abstract !hasdefault java.lang.Class include() meth public abstract !hasdefault java.lang.Class exceptionHandler() meth public abstract !hasdefault java.lang.String name() meth public abstract !hasdefault java.lang.String[] documentation() meth public abstract !hasdefault org.graalvm.nativeimage.c.function.CEntryPoint$Builtin builtin() +CLSS public final static org.graalvm.nativeimage.c.function.CEntryPoint$AlwaysIncluded + outer org.graalvm.nativeimage.c.function.CEntryPoint +intf java.util.function.BooleanSupplier +meth public boolean getAsBoolean() +supr java.lang.Object + CLSS public final static !enum org.graalvm.nativeimage.c.function.CEntryPoint$Builtin outer org.graalvm.nativeimage.c.function.CEntryPoint fld public final static org.graalvm.nativeimage.c.function.CEntryPoint$Builtin ATTACH_THREAD @@ -493,6 +506,12 @@ CLSS public abstract interface static !annotation org.graalvm.nativeimage.c.func anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[PARAMETER]) intf java.lang.annotation.Annotation +CLSS public final static org.graalvm.nativeimage.c.function.CEntryPoint$NotIncludedAutomatically + outer org.graalvm.nativeimage.c.function.CEntryPoint +intf java.util.function.BooleanSupplier +meth public boolean getAsBoolean() +supr java.lang.Object + CLSS public final org.graalvm.nativeimage.c.function.CEntryPointLiteral<%0 extends org.graalvm.nativeimage.c.function.CFunctionPointer> meth public !varargs static <%0 extends org.graalvm.nativeimage.c.function.CFunctionPointer> org.graalvm.nativeimage.c.function.CEntryPointLiteral<{%%0}> create(java.lang.Class,java.lang.String,java.lang.Class[]) meth public {org.graalvm.nativeimage.c.function.CEntryPointLiteral%0} getFunctionPointer() diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java index a9534889435d..94a3090fc1fd 100644 --- a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java +++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -143,7 +143,7 @@ public static boolean inImageBuildtimeCode() { } /** - * Returns true if the image is build as an executable. + * Returns true if the image is built as an executable. * * @since 19.0 */ diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/c/function/CEntryPoint.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/c/function/CEntryPoint.java index 89c27d7207dc..853d0a91d48b 100644 --- a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/c/function/CEntryPoint.java +++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/c/function/CEntryPoint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -44,6 +44,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.util.function.BooleanSupplier; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.Isolate; @@ -135,6 +136,60 @@ private FatalExceptionHandler() { */ Builtin builtin() default Builtin.NO_BUILTIN; + /** + * If the supplier returns {@code true}, this entry point is added automatically when building a + * shared library. This means the method is a root method for compilation, and everything + * reachable from it is compiled too. + * + * The provided class must have a nullary constructor, which is used to instantiate the class. + * Then the supplier function is called on the newly instantiated instance. + * + * @since 22.0 + */ + Class include() default AlwaysIncluded.class; + + /** + * A {@link BooleanSupplier} that always returns {@code true}. + * + * @since 22.0 + */ + final class AlwaysIncluded implements BooleanSupplier { + + private AlwaysIncluded() { + } + + /** + * Returns {@code true}. + * + * @since 22.0 + */ + @Override + public boolean getAsBoolean() { + return true; + } + } + + /** + * A {@link BooleanSupplier} that always returns {@code false}. + * + * @since 22.0 + */ + final class NotIncludedAutomatically implements BooleanSupplier { + + private NotIncludedAutomatically() { + } + + /** + * Returns {@code false}. + * + * @since 22.0 + */ + @Override + public boolean getAsBoolean() { + return false; + } + } + /** * The built-in methods which can be {@linkplain #builtin() aliased}. * diff --git a/sdk/src/org.graalvm.options/src/org/graalvm/options/OptionDescriptor.java b/sdk/src/org.graalvm.options/src/org/graalvm/options/OptionDescriptor.java index 9b88f8120277..429cbdb5ccff 100644 --- a/sdk/src/org.graalvm.options/src/org/graalvm/options/OptionDescriptor.java +++ b/sdk/src/org.graalvm.options/src/org/graalvm/options/OptionDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -96,7 +96,7 @@ public boolean isDeprecated() { } /** - * Returns the deprecation reason and the recommended fix. + * Returns the deprecation reason and the recommended fix. For newlines, use %n. * * @since 20.1.0 */ @@ -133,7 +133,8 @@ public OptionStability getStability() { } /** - * Returns a human-readable description on how to use the option. + * Returns a human-readable description on how to use the option. For newlines, use + * %n. * * @since 19.0 */ diff --git a/sdk/src/org.graalvm.polyglot/snapshot.sigtest b/sdk/src/org.graalvm.polyglot/snapshot.sigtest index 632579394e7b..f49816641c7b 100644 --- a/sdk/src/org.graalvm.polyglot/snapshot.sigtest +++ b/sdk/src/org.graalvm.polyglot/snapshot.sigtest @@ -178,8 +178,9 @@ meth public org.graalvm.polyglot.Context$Builder processHandler(org.graalvm.poly meth public org.graalvm.polyglot.Context$Builder resourceLimits(org.graalvm.polyglot.ResourceLimits) meth public org.graalvm.polyglot.Context$Builder serverTransport(org.graalvm.polyglot.io.MessageTransport) meth public org.graalvm.polyglot.Context$Builder timeZone(java.time.ZoneId) +meth public org.graalvm.polyglot.Context$Builder useSystemExit(boolean) supr java.lang.Object -hfds allowAllAccess,allowCreateProcess,allowCreateThread,allowExperimentalOptions,allowHostAccess,allowHostClassLoading,allowIO,allowNativeAccess,allowValueSharing,arguments,currentWorkingDirectory,customFileSystem,customLogHandler,environment,environmentAccess,err,hostAccess,hostClassFilter,hostClassLoader,in,messageTransport,onlyLanguages,options,out,polyglotAccess,processHandler,resourceLimits,sharedEngine,zone +hfds allowAllAccess,allowCreateProcess,allowCreateThread,allowExperimentalOptions,allowHostAccess,allowHostClassLoading,allowIO,allowNativeAccess,allowValueSharing,arguments,currentWorkingDirectory,customFileSystem,customLogHandler,environment,environmentAccess,err,hostAccess,hostClassFilter,hostClassLoader,in,messageTransport,onlyLanguages,options,out,polyglotAccess,processHandler,resourceLimits,sharedEngine,useSystemExit,zone CLSS public final org.graalvm.polyglot.Engine innr public final Builder diff --git a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Context.java b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Context.java index 55953f2dcfec..1379b19e3a0b 100644 --- a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Context.java +++ b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Context.java @@ -293,6 +293,26 @@ * currently executing code. If the context is currently executing some code, a different thread may * kill the running execution and close the context using {@link #close(boolean)}. * + *

    Context Exit

    + * + * A context is exited naturally by calling the {@link #close} method. A context may also be exited + * at the guest application request. There are two ways a guest language may exit. + *
      + *
    • Soft exit. A guest language throws a special exception that causes the embedder thread to + * eventually throw a {@link PolyglotException} with {@link PolyglotException#isExit()} returning + * true and {@link PolyglotException#getExitStatus()} returning the exit status code + * specified by the guest application. The special exception does not influence other threads and + * does not trigger context close on its own. Closing the context is up to the embedder. + *
    • Hard exit. A guest language uses a builtin command that unwinds all context threads and + * closes the context by force. Embedder threads also throw a {@link PolyglotException} with + * {@link PolyglotException#isExit()} returning true and + * {@link PolyglotException#getExitStatus()} returning the exit status code specified by the guest + * application. However, the context is closed automatically. The hard exit can be customized using + * {@link Builder#useSystemExit(boolean)}. If true, the context threads are unwound by + * calling {@link System#exit(int)} with the exit status parameter specified by the guest + * application. This operation terminates the whole host application. + *
    + * *

    Pre-Initialization

    * * The context pre-initialization can be used to perform expensive builtin creation in the time of @@ -376,7 +396,7 @@ public Engine getEngine() { * @since 19.0 */ public Value eval(Source source) { - return dispatch.eval(receiver, source.getLanguage(), source.receiver); + return dispatch.eval(receiver, source.getLanguage(), source); } /** @@ -457,7 +477,7 @@ public Value eval(String languageId, CharSequence source) { * @since 20.2 */ public Value parse(Source source) throws PolyglotException { - return dispatch.parse(receiver, source.getLanguage(), source.receiver); + return dispatch.parse(receiver, source.getLanguage(), source); } /** @@ -1024,6 +1044,7 @@ public final class Builder { private ZoneId zone; private Path currentWorkingDirectory; private ClassLoader hostClassLoader; + private boolean useSystemExit; Builder(String... onlyLanguages) { Objects.requireNonNull(onlyLanguages); @@ -1684,6 +1705,18 @@ public Builder hostClassLoader(ClassLoader classLoader) { return this; } + /** + * Specifies whether {@link System#exit(int)} may be used to improve efficiency of stack + * unwinding for context exit requested by the guest application. + * + * @since 22.0 + * @see Context + */ + public Builder useSystemExit(boolean enabled) { + this.useSystemExit = enabled; + return this; + } + /** * Creates a new context instance from the configuration provided in the builder. The same * context builder can be used to create multiple context instances. @@ -1796,7 +1829,7 @@ public Context build() { io, hostClassLoading, experimentalOptions, localHostLookupFilter, contextOptions, arguments == null ? Collections.emptyMap() : arguments, onlyLanguages, customFileSystem, customLogHandler, createProcess, processHandler, environmentAccess, environment, zone, limits, - localCurrentWorkingDirectory, hostClassLoader, allowValueSharing); + localCurrentWorkingDirectory, hostClassLoader, allowValueSharing, useSystemExit); return ctx; } diff --git a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Engine.java b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Engine.java index 1f2171764020..4029ae61f75a 100644 --- a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Engine.java +++ b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Engine.java @@ -44,7 +44,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.Reader; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Executable; import java.lang.reflect.Method; @@ -85,12 +84,12 @@ import org.graalvm.polyglot.impl.AbstractPolyglotImpl.AbstractExceptionDispatch; import org.graalvm.polyglot.impl.AbstractPolyglotImpl.AbstractInstrumentDispatch; import org.graalvm.polyglot.impl.AbstractPolyglotImpl.AbstractLanguageDispatch; +import org.graalvm.polyglot.impl.AbstractPolyglotImpl.AbstractSourceDispatch; +import org.graalvm.polyglot.impl.AbstractPolyglotImpl.AbstractSourceSectionDispatch; import org.graalvm.polyglot.impl.AbstractPolyglotImpl.AbstractStackFrameImpl; import org.graalvm.polyglot.impl.AbstractPolyglotImpl.AbstractValueDispatch; -import org.graalvm.polyglot.io.ByteSequence; import org.graalvm.polyglot.io.FileSystem; import org.graalvm.polyglot.io.MessageTransport; -import org.graalvm.polyglot.management.ExecutionEvent; /** * An execution engine for Graal {@linkplain Language guest languages} that allows to inspect the @@ -625,13 +624,13 @@ public Value newValue(AbstractValueDispatch dispatch, Object context, Object rec } @Override - public Source newSource(Object receiver) { - return new Source(receiver); + public Source newSource(AbstractSourceDispatch dispatch, Object receiver) { + return new Source(dispatch, receiver); } @Override - public SourceSection newSourceSection(Source source, Object receiver) { - return new SourceSection(source, receiver); + public SourceSection newSourceSection(Source source, AbstractSourceSectionDispatch dispatch, Object receiver) { + return new SourceSection(source, dispatch, receiver); } @Override @@ -654,6 +653,16 @@ public AbstractEngineDispatch getDispatch(Engine engine) { return engine.dispatch; } + @Override + public AbstractSourceDispatch getDispatch(Source source) { + return source.dispatch; + } + + @Override + public AbstractSourceSectionDispatch getDispatch(SourceSection sourceSection) { + return sourceSection.dispatch; + } + @Override public ResourceLimitEvent newResourceLimitsEvent(Context context) { return new ResourceLimitEvent(context); @@ -669,6 +678,16 @@ public Object getReceiver(ResourceLimits value) { return value.receiver; } + @Override + public Object getReceiver(Source source) { + return source.receiver; + } + + @Override + public Object getReceiver(SourceSection sourceSection) { + return sourceSection.receiver; + } + @Override public PolyglotException newLanguageException(String message, AbstractExceptionDispatch dispatch, Object receiver) { return new PolyglotException(message, dispatch, receiver); @@ -787,7 +806,7 @@ public String validatePolyglotAccess(PolyglotAccess access, UnmodifiableEconomic private static final boolean JDK8_OR_EARLIER = System.getProperty("java.specification.version").compareTo("1.9") < 0; - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "deprecation"}) private static AbstractPolyglotImpl initEngineImpl() { return AccessController.doPrivileged(new PrivilegedAction() { public AbstractPolyglotImpl run() { @@ -860,8 +879,6 @@ static Iterator createInvalidPolyglotImpl() { private static class PolyglotInvalid extends AbstractPolyglotImpl { - private final EmptySource source = new EmptySource(this); - /** * Forces ahead-of-time initialization. * @@ -870,6 +887,7 @@ private static class PolyglotInvalid extends AbstractPolyglotImpl { static boolean AOT; static { + @SuppressWarnings("deprecation") Boolean aot = AccessController.doPrivileged(new PrivilegedAction() { public Boolean run() { return Boolean.getBoolean("com.oracle.graalvm.isaot"); @@ -909,65 +927,6 @@ public AbstractHostAccess createHostAccess() { throw noPolyglotImplementationFound(); } - @Override - public AbstractManagementDispatch getManagementDispatch() { - return new AbstractManagementDispatch(this) { - - @Override - public boolean isExecutionEventStatement(Object impl) { - return false; - } - - @Override - public boolean isExecutionEventRoot(Object impl) { - return false; - } - - @Override - public boolean isExecutionEventExpression(Object impl) { - return false; - } - - @Override - public String getExecutionEventRootName(Object impl) { - throw noPolyglotImplementationFound(); - } - - @Override - public PolyglotException getExecutionEventException(Object impl) { - throw noPolyglotImplementationFound(); - } - - @Override - public Value getExecutionEventReturnValue(Object impl) { - throw noPolyglotImplementationFound(); - } - - @Override - public SourceSection getExecutionEventLocation(Object impl) { - throw noPolyglotImplementationFound(); - } - - @Override - public List getExecutionEventInputValues(Object impl) { - throw noPolyglotImplementationFound(); - } - - @Override - public void closeExecutionListener(Object impl) { - throw noPolyglotImplementationFound(); - } - - @Override - public Object attachExecutionListener(Object engine, Consumer onEnter, Consumer onReturn, boolean expressions, boolean statements, - boolean roots, - Predicate sourceFilter, Predicate rootFilter, boolean collectInputValues, boolean collectReturnValues, boolean collectErrors) { - throw noPolyglotImplementationFound(); - } - - }; - } - private static RuntimeException noPolyglotImplementationFound() { String suggestion; if (AOT) { @@ -978,16 +937,6 @@ private static RuntimeException noPolyglotImplementationFound() { return new IllegalStateException("No language and polyglot implementation was found on the classpath. " + suggestion); } - @Override - public AbstractSourceDispatch getSourceDispatch() { - return source; - } - - @Override - public AbstractSourceSectionDispatch getSourceSectionDispatch() { - throw new UnsupportedOperationException(); - } - @Override public Class loadLanguageClass(String className) { return null; @@ -1016,168 +965,40 @@ public FileSystem newDefaultFileSystem() { throw noPolyglotImplementationFound(); } - static class EmptySource extends AbstractSourceDispatch { - - protected EmptySource(AbstractPolyglotImpl engineImpl) { - super(engineImpl); - } - - @Override - public Source build(String language, Object origin, URI uri, String name, String mimeType, Object content, boolean interactive, boolean internal, boolean cached, Charset encoding) - throws IOException { - throw noPolyglotImplementationFound(); - } - - @Override - public String getLanguage(Object impl) { - throw new UnsupportedOperationException(); - } - - @Override - public String findLanguage(File file) throws IOException { - return null; - } - - @Override - public String findLanguage(URL url) throws IOException { - return null; - } - - @Override - public String findMimeType(File file) throws IOException { - return null; - } - - @Override - public String findMimeType(URL url) throws IOException { - return null; - } - - @Override - public String getMimeType(Object impl) { - throw new UnsupportedOperationException(); - } - - @Override - public String findLanguage(String mimeType) { - return null; - } - - @Override - public String getName(Object impl) { - throw new UnsupportedOperationException(); - } - - @Override - public String getPath(Object impl) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isInteractive(Object impl) { - throw new UnsupportedOperationException(); - } - - @Override - public URL getURL(Object impl) { - throw new UnsupportedOperationException(); - } - - @Override - public URI getURI(Object impl) { - throw new UnsupportedOperationException(); - } - - @Override - public Reader getReader(Object impl) { - throw new UnsupportedOperationException(); - } - - @Override - public InputStream getInputStream(Object impl) { - throw new UnsupportedOperationException(); - } - - @Override - public int getLength(Object impl) { - throw new UnsupportedOperationException(); - } - - @Override - public CharSequence getCharacters(Object impl) { - throw new UnsupportedOperationException(); - } - - @Override - public CharSequence getCharacters(Object impl, int lineNumber) { - throw new UnsupportedOperationException(); - } - - @Override - public int getLineCount(Object impl) { - throw new UnsupportedOperationException(); - } - - @Override - public int getLineNumber(Object impl, int offset) { - throw new UnsupportedOperationException(); - } - - @Override - public int getColumnNumber(Object impl, int offset) { - throw new UnsupportedOperationException(); - } - - @Override - public int getLineStartOffset(Object impl, int lineNumber) { - throw new UnsupportedOperationException(); - } - - @Override - public int getLineLength(Object impl, int lineNumber) { - throw new UnsupportedOperationException(); - } - - @Override - public String toString(Object impl) { - throw new UnsupportedOperationException(); - } - - @Override - public int hashCode(Object impl) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean equals(Object impl, Object otherImpl) { - throw new UnsupportedOperationException(); - } + @Override + public Object newTargetTypeMapping(Class sourceType, Class targetType, Predicate acceptsValue, Function convertValue, TargetMappingPrecedence precedence) { + return new Object(); + } - @Override - public boolean isInternal(Object impl) { - throw new UnsupportedOperationException(); - } + @Override + public Source build(String language, Object origin, URI uri, String name, String mimeType, Object content, boolean interactive, boolean internal, boolean cached, Charset encoding) + throws IOException { + throw noPolyglotImplementationFound(); + } - @Override - public ByteSequence getBytes(Object impl) { - throw new UnsupportedOperationException(); - } + @Override + public String findLanguage(File file) throws IOException { + return null; + } - @Override - public boolean hasCharacters(Object impl) { - throw new UnsupportedOperationException(); - } + @Override + public String findLanguage(URL url) throws IOException { + return null; + } - @Override - public boolean hasBytes(Object impl) { - throw new UnsupportedOperationException(); - } + @Override + public String findMimeType(File file) throws IOException { + return null; + } + @Override + public String findMimeType(URL url) throws IOException { + return null; } @Override - public Object newTargetTypeMapping(Class sourceType, Class targetType, Predicate acceptsValue, Function convertValue, TargetMappingPrecedence precedence) { - return new Object(); + public String findLanguage(String mimeType) { + return null; } } diff --git a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/PolyglotException.java b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/PolyglotException.java index 06161bb2c7c3..e4e8b88fc6dd 100644 --- a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/PolyglotException.java +++ b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/PolyglotException.java @@ -328,10 +328,11 @@ public boolean isInterrupted() { /** * Returns true if this exception is caused by an attempt of a guest language - * program to exit the application using a builtin command. The provided exit code can be - * accessed using {@link #getExitStatus()}. + * program to exit the application. The provided exit code can be accessed using + * {@link #getExitStatus()}. This can be the result of either the soft or the hard exit. * * @since 19.0 + * @see Context */ public boolean isExit() { return dispatch.isExit(impl); @@ -378,9 +379,11 @@ public Value getGuestObject() { /** * Returns the exit status if this exception indicates that the application was {@link #isExit() - * exited}. The exit status is intended to be passed to {@link System#exit(int)}. + * exited}. The exit status is intended to be passed to {@link System#exit(int)}. In case of + * hard exit the application can be configured to call {@link System#exit(int)} directly using + * {@link Context.Builder#useSystemExit(boolean)}. * - * @see #isExit() + * @see Context * @since 19.0 */ public int getExitStatus() { diff --git a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Source.java b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Source.java index 6479250dd04b..62ffc5c43039 100644 --- a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Source.java +++ b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Source.java @@ -51,6 +51,7 @@ import java.nio.charset.Charset; import java.util.Objects; +import org.graalvm.polyglot.impl.AbstractPolyglotImpl; import org.graalvm.polyglot.impl.AbstractPolyglotImpl.AbstractSourceDispatch; import org.graalvm.polyglot.io.ByteSequence; @@ -130,24 +131,25 @@ */ public final class Source { - private static volatile AbstractSourceDispatch DISPATCH; + private static volatile AbstractPolyglotImpl IMPL; - static AbstractSourceDispatch getReceiver() { - if (DISPATCH == null) { + static AbstractPolyglotImpl getImpl() { + if (IMPL == null) { synchronized (Engine.class) { - if (DISPATCH == null) { - DISPATCH = Engine.getImpl().getSourceDispatch(); - SourceSection.DISPATCH = Engine.getImpl().getSourceSectionDispatch(); + if (IMPL == null) { + IMPL = Engine.getImpl(); } } } - return DISPATCH; + return IMPL; } + final AbstractSourceDispatch dispatch; final Object receiver; - Source(Object impl) { - this.receiver = impl; + Source(AbstractSourceDispatch dispatch, Object receiver) { + this.dispatch = dispatch; + this.receiver = receiver; } /** @@ -157,7 +159,7 @@ static AbstractSourceDispatch getReceiver() { * @since 19.0 */ public String getLanguage() { - return getReceiver().getLanguage(receiver); + return dispatch.getLanguage(receiver); } /** @@ -170,7 +172,7 @@ public String getLanguage() { * @since 19.0 */ public String getName() { - return getReceiver().getName(receiver); + return dispatch.getName(receiver); } /** @@ -182,7 +184,7 @@ public String getName() { * @since 19.0 */ public String getPath() { - return getReceiver().getPath(receiver); + return dispatch.getPath(receiver); } /** @@ -192,7 +194,7 @@ public String getPath() { * @since 19.0 */ public URL getURL() { - return getReceiver().getURL(receiver); + return dispatch.getURL(receiver); } /** @@ -206,7 +208,7 @@ public URL getURL() { * @since 19.0 */ public URI getURI() { - return getReceiver().getURI(receiver); + return dispatch.getURI(receiver); } /** @@ -221,7 +223,7 @@ public URI getURI() { * @since 19.0 */ public boolean isInteractive() { - return getReceiver().isInteractive(receiver); + return dispatch.isInteractive(receiver); } /** @@ -240,7 +242,7 @@ public boolean isInteractive() { * @since 19.0 */ public boolean isInternal() { - return getReceiver().isInternal(receiver); + return dispatch.isInternal(receiver); } /** @@ -252,7 +254,7 @@ public boolean isInternal() { * @since 19.0 */ public Reader getReader() { - return getReceiver().getReader(receiver); + return dispatch.getReader(receiver); } /** @@ -263,7 +265,7 @@ public Reader getReader() { */ @Deprecated public InputStream getInputStream() { - return getReceiver().getInputStream(receiver); + return dispatch.getInputStream(receiver); } /** @@ -272,7 +274,7 @@ public InputStream getInputStream() { * @since 19.0 */ public int getLength() { - return getReceiver().getLength(receiver); + return dispatch.getLength(receiver); } /** @@ -283,7 +285,7 @@ public int getLength() { * @since 19.0 */ public CharSequence getCharacters() { - return getReceiver().getCharacters(receiver); + return dispatch.getCharacters(receiver); } /** @@ -307,7 +309,7 @@ public CharSequence getCharacters() { * @since 19.0 */ public String getMimeType() { - return getReceiver().getMimeType(receiver); + return dispatch.getMimeType(receiver); } /** @@ -320,7 +322,7 @@ public String getMimeType() { * @since 19.0 */ public CharSequence getCharacters(int lineNumber) { - return getReceiver().getCharacters(receiver, lineNumber); + return dispatch.getCharacters(receiver, lineNumber); } /** @@ -332,7 +334,7 @@ public CharSequence getCharacters(int lineNumber) { * @since 19.0 */ public ByteSequence getBytes() { - return getReceiver().getBytes(receiver); + return dispatch.getBytes(receiver); } /** @@ -355,7 +357,7 @@ public ByteSequence getBytes() { * @since 19.0 */ public boolean hasCharacters() { - return getReceiver().hasCharacters(receiver); + return dispatch.hasCharacters(receiver); } /** @@ -369,7 +371,7 @@ public boolean hasCharacters() { * @since 19.0 */ public boolean hasBytes() { - return getReceiver().hasBytes(receiver); + return dispatch.hasBytes(receiver); } /** @@ -382,7 +384,7 @@ public boolean hasBytes() { * @since 19.0 */ public int getLineCount() { - return getReceiver().getLineCount(receiver); + return dispatch.getLineCount(receiver); } /** @@ -395,7 +397,7 @@ public int getLineCount() { * @since 19.0 */ public int getLineNumber(int offset) throws IllegalArgumentException { - return getReceiver().getLineNumber(receiver, offset); + return dispatch.getLineNumber(receiver, offset); } /** @@ -408,7 +410,7 @@ public int getLineNumber(int offset) throws IllegalArgumentException { * @since 19.0 */ public int getColumnNumber(int offset) throws IllegalArgumentException { - return getReceiver().getColumnNumber(receiver, offset); + return dispatch.getColumnNumber(receiver, offset); } /** @@ -420,7 +422,7 @@ public int getColumnNumber(int offset) throws IllegalArgumentException { * @since 19.0 */ public int getLineStartOffset(int lineNumber) throws IllegalArgumentException { - return getReceiver().getLineStartOffset(receiver, lineNumber); + return dispatch.getLineStartOffset(receiver, lineNumber); } /** @@ -433,7 +435,7 @@ public int getLineStartOffset(int lineNumber) throws IllegalArgumentException { * @since 19.0 */ public int getLineLength(int lineNumber) throws IllegalArgumentException { - return getReceiver().getLineLength(receiver, lineNumber); + return dispatch.getLineLength(receiver, lineNumber); } /** @@ -443,7 +445,7 @@ public int getLineLength(int lineNumber) throws IllegalArgumentException { */ @Override public String toString() { - return getReceiver().toString(receiver); + return dispatch.toString(receiver); } /** @@ -453,7 +455,7 @@ public String toString() { */ @Override public int hashCode() { - return getReceiver().hashCode(receiver); + return dispatch.hashCode(receiver); } /** @@ -469,7 +471,7 @@ public boolean equals(Object obj) { } else { return false; } - return getReceiver().equals(receiver, otherImpl); + return dispatch.equals(receiver, otherImpl); } /** @@ -591,7 +593,7 @@ public static Source create(String language, CharSequence source) { * @since 19.0 */ public static String findLanguage(File file) throws IOException { - return getReceiver().findLanguage(file); + return getImpl().findLanguage(file); } /** @@ -612,7 +614,7 @@ public static String findLanguage(File file) throws IOException { * @since 19.0 */ public static String findLanguage(URL url) throws IOException { - return getReceiver().findLanguage(url); + return getImpl().findLanguage(url); } /** @@ -625,7 +627,7 @@ public static String findLanguage(URL url) throws IOException { * @since 19.0 */ public static String findMimeType(File file) throws IOException { - return getReceiver().findMimeType(file); + return getImpl().findMimeType(file); } /** @@ -640,7 +642,7 @@ public static String findMimeType(File file) throws IOException { * @since 19.0 */ public static String findMimeType(URL url) throws IOException { - return getReceiver().findMimeType(url); + return getImpl().findMimeType(url); } /** @@ -652,7 +654,7 @@ public static String findMimeType(URL url) throws IOException { * @since 19.0 */ public static String findLanguage(String mimeType) { - return getReceiver().findLanguage(mimeType); + return getImpl().findLanguage(mimeType); } @SuppressWarnings({"unchecked", "unused"}) @@ -677,7 +679,7 @@ private static IllegalArgumentException invalidMimeType(String mimeType) { return new IllegalArgumentException(String.format("Invalid MIME type '%s' provided. A MIME type consists of a type and a subtype separated by '/'.", mimeType)); } - private static final Source EMPTY = new Source(null); + private static final Source EMPTY = new Source(null, null); /** * Represents a builder to build {@link Source} objects. @@ -915,7 +917,7 @@ public Builder encoding(Charset encoding) { * @since 19.0 */ public Source build() throws IOException { - Source source = getReceiver().build(language, origin, uri, name, mimeType, content, interactive, internal, cached, fileEncoding); + Source source = getImpl().build(language, origin, uri, name, mimeType, content, interactive, internal, cached, fileEncoding); // make sure origin is not consumed again if builder is used twice if (source.hasBytes()) { diff --git a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/SourceSection.java b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/SourceSection.java index 8e6a3b19f17b..3e4c0a357460 100644 --- a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/SourceSection.java +++ b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/SourceSection.java @@ -54,13 +54,13 @@ */ public final class SourceSection { - static volatile AbstractSourceSectionDispatch DISPATCH; - final Source source; + final AbstractSourceSectionDispatch dispatch; final Object receiver; - SourceSection(Source source, Object receiver) { + SourceSection(Source source, AbstractSourceSectionDispatch dispatch, Object receiver) { this.source = source; + this.dispatch = dispatch; this.receiver = receiver; } @@ -73,7 +73,7 @@ public final class SourceSection { * @since 19.0 */ public boolean isAvailable() { - return DISPATCH.isAvailable(receiver); + return dispatch.isAvailable(receiver); } /** @@ -85,7 +85,7 @@ public boolean isAvailable() { * @since 19.0 */ public boolean hasLines() { - return DISPATCH.hasLines(receiver); + return dispatch.hasLines(receiver); } /** @@ -98,7 +98,7 @@ public boolean hasLines() { * @since 19.0 */ public boolean hasColumns() { - return DISPATCH.hasColumns(receiver); + return dispatch.hasColumns(receiver); } /** @@ -111,7 +111,7 @@ public boolean hasColumns() { * @since 19.0 */ public boolean hasCharIndex() { - return DISPATCH.hasCharIndex(receiver); + return dispatch.hasCharIndex(receiver); } /** @@ -134,7 +134,7 @@ public Source getSource() { * @since 19.0 */ public int getStartLine() { - return DISPATCH.getStartLine(receiver); + return dispatch.getStartLine(receiver); } /** @@ -147,7 +147,7 @@ public int getStartLine() { * @since 19.0 */ public int getStartColumn() { - return DISPATCH.getStartColumn(receiver); + return dispatch.getStartColumn(receiver); } /** @@ -160,7 +160,7 @@ public int getStartColumn() { * @since 19.0 */ public int getEndLine() { - return DISPATCH.getEndLine(receiver); + return dispatch.getEndLine(receiver); } /** @@ -173,7 +173,7 @@ public int getEndLine() { * @since 19.0 */ public int getEndColumn() { - return DISPATCH.getEndColumn(receiver); + return dispatch.getEndColumn(receiver); } /** @@ -187,7 +187,7 @@ public int getEndColumn() { * @since 19.0 */ public int getCharIndex() { - return DISPATCH.getCharIndex(receiver); + return dispatch.getCharIndex(receiver); } /** @@ -201,7 +201,7 @@ public int getCharIndex() { * @since 19.0 */ public int getCharLength() { - return DISPATCH.getCharLength(receiver); + return dispatch.getCharLength(receiver); } /** @@ -215,7 +215,7 @@ public int getCharLength() { * @since 19.0 */ public int getCharEndIndex() { - return DISPATCH.getCharEndIndex(receiver); + return dispatch.getCharEndIndex(receiver); } /** @@ -224,7 +224,7 @@ public int getCharEndIndex() { */ @Deprecated public CharSequence getCode() { - return DISPATCH.getCode(receiver); + return dispatch.getCode(receiver); } /** @@ -235,7 +235,7 @@ public CharSequence getCode() { * @since 19.0 */ public CharSequence getCharacters() { - return DISPATCH.getCode(receiver); + return dispatch.getCode(receiver); } /** @@ -247,13 +247,13 @@ public CharSequence getCharacters() { */ @Override public String toString() { - return DISPATCH.toString(receiver); + return dispatch.toString(receiver); } /** @since 19.0 or earlier */ @Override public int hashCode() { - return DISPATCH.hashCode(receiver); + return dispatch.hashCode(receiver); } /** @since 19.0 or earlier */ @@ -267,7 +267,7 @@ public boolean equals(Object obj) { if (otherImpl instanceof SourceSection) { otherImpl = ((SourceSection) obj).receiver; } - return DISPATCH.equals(receiver, otherImpl); + return dispatch.equals(receiver, otherImpl); } } diff --git a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/impl/AbstractPolyglotImpl.java b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/impl/AbstractPolyglotImpl.java index 3dd202ce7013..3da7f585210f 100644 --- a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/impl/AbstractPolyglotImpl.java +++ b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/impl/AbstractPolyglotImpl.java @@ -93,6 +93,7 @@ import org.graalvm.polyglot.io.MessageTransport; import org.graalvm.polyglot.io.ProcessHandler; import org.graalvm.polyglot.management.ExecutionEvent; +import org.graalvm.polyglot.management.ExecutionListener; /** * This class is intended to be used by polyglot implementations. Methods in this class are not @@ -114,8 +115,17 @@ protected ManagementAccess() { } } - public abstract ExecutionEvent newExecutionEvent(Object event); + public abstract ExecutionListener newExecutionListener(AbstractManagementDispatch dispatch, Object receiver); + public abstract ExecutionEvent newExecutionEvent(AbstractManagementDispatch dispatch, Object event); + + public abstract Object getReceiver(ExecutionListener executionListener); + + public abstract AbstractManagementDispatch getDispatch(ExecutionListener executionListener); + + public abstract Object getReceiver(ExecutionEvent executionEvent); + + public abstract AbstractManagementDispatch getDispatch(ExecutionEvent executionEvent); } public abstract static class IOAccess { @@ -151,9 +161,9 @@ protected APIAccess() { public abstract Value newValue(AbstractValueDispatch dispatch, Object context, Object receiver); - public abstract Source newSource(Object receiver); + public abstract Source newSource(AbstractSourceDispatch dispatch, Object receiver); - public abstract SourceSection newSourceSection(Source source, Object receiver); + public abstract SourceSection newSourceSection(Source source, AbstractSourceSectionDispatch dispatch, Object receiver); public abstract PolyglotException newLanguageException(String message, AbstractExceptionDispatch dispatch, Object receiver); @@ -169,6 +179,10 @@ protected APIAccess() { public abstract Object getReceiver(ResourceLimits value); + public abstract Object getReceiver(Source source); + + public abstract Object getReceiver(SourceSection sourceSection); + public abstract AbstractValueDispatch getDispatch(Value value); public abstract Object getContext(Value value); @@ -183,6 +197,10 @@ protected APIAccess() { public abstract AbstractContextDispatch getDispatch(Context context); + public abstract AbstractSourceDispatch getDispatch(Source source); + + public abstract AbstractSourceSectionDispatch getDispatch(SourceSection sourceSection); + public abstract ResourceLimitEvent newResourceLimitsEvent(Context context); public abstract StackFrame newPolyglotStackTraceElement(AbstractStackFrameImpl dispatch, Object receiver); @@ -284,11 +302,18 @@ public abstract Engine buildEngine(OutputStream out, OutputStream err, InputStre public abstract void resetPreInitializedEngine(); - public abstract AbstractSourceDispatch getSourceDispatch(); + public abstract Source build(String language, Object origin, URI uri, String name, String mimeType, Object content, boolean interactive, boolean internal, boolean cached, Charset encoding) + throws IOException; - public abstract AbstractSourceSectionDispatch getSourceSectionDispatch(); + public abstract String findLanguage(File file) throws IOException; - public abstract AbstractManagementDispatch getManagementDispatch(); + public abstract String findLanguage(URL url) throws IOException; + + public abstract String findLanguage(String mimeType); + + public abstract String findMimeType(File file) throws IOException; + + public abstract String findMimeType(URL url) throws IOException; /** * Returns the default host dispatch of this polyglot abstraction. @@ -324,13 +349,6 @@ public final AbstractPolyglotImpl getPolyglotImpl() { public abstract void closeExecutionListener(Object impl); - public abstract Object attachExecutionListener(Object engine, Consumer onEnter, - Consumer onReturn, - boolean expressions, - boolean statements, - boolean roots, - Predicate sourceFilter, Predicate rootFilter, boolean collectInputValues, boolean collectReturnValues, boolean collectExceptions); - public abstract PolyglotException getExecutionEventException(Object impl); } @@ -344,9 +362,6 @@ protected AbstractSourceDispatch(AbstractPolyglotImpl engineImpl) { this.engineImpl = engineImpl; } - public abstract Source build(String language, Object origin, URI uri, String name, String mimeType, Object content, boolean interactive, boolean internal, boolean cached, Charset encoding) - throws IOException; - public abstract String getName(Object impl); public abstract String getPath(Object impl); @@ -385,16 +400,6 @@ public abstract Source build(String language, Object origin, URI uri, String nam public abstract boolean isInternal(Object impl); - public abstract String findLanguage(File file) throws IOException; - - public abstract String findLanguage(URL url) throws IOException; - - public abstract String findLanguage(String mimeType); - - public abstract String findMimeType(File file) throws IOException; - - public abstract String findMimeType(URL url) throws IOException; - public abstract ByteSequence getBytes(Object impl); public abstract boolean hasCharacters(Object impl); @@ -453,9 +458,9 @@ protected AbstractContextDispatch(AbstractPolyglotImpl impl) { public abstract boolean initializeLanguage(Object receiver, String languageId); - public abstract Value eval(Object receiver, String language, Object sourceImpl); + public abstract Value eval(Object receiver, String language, Source source); - public abstract Value parse(Object receiver, String language, Object sourceImpl); + public abstract Value parse(Object receiver, String language, Source source); public abstract void close(Object receiver, boolean cancelIfExecuting); @@ -507,7 +512,7 @@ public abstract Context createContext(Object receiver, OutputStream out, OutputS Map options, Map arguments, String[] onlyLanguages, FileSystem fileSystem, Object logHandlerOrStream, boolean allowCreateProcess, ProcessHandler processHandler, EnvironmentAccess environmentAccess, Map environment, ZoneId zone, Object limitsImpl, String currentWorkingDirectory, ClassLoader hostClassLoader, - boolean allowValueSharing); + boolean allowValueSharing, boolean useSystemExit); public abstract String getImplementationName(Object receiver); @@ -515,6 +520,13 @@ public abstract Context createContext(Object receiver, OutputStream out, OutputS public abstract String getVersion(Object receiver); + public abstract ExecutionListener attachExecutionListener(Object engine, Consumer onEnter, + Consumer onReturn, + boolean expressions, + boolean statements, + boolean roots, + Predicate sourceFilter, Predicate rootFilter, boolean collectInputValues, boolean collectReturnValues, boolean collectExceptions); + } public abstract static class AbstractExceptionDispatch { diff --git a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/management/ExecutionEvent.java b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/management/ExecutionEvent.java index aae49f709069..29ba91416d65 100644 --- a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/management/ExecutionEvent.java +++ b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/management/ExecutionEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -45,7 +45,8 @@ import org.graalvm.polyglot.PolyglotException; import org.graalvm.polyglot.SourceSection; import org.graalvm.polyglot.Value; -import static org.graalvm.polyglot.management.Management.IMPL; + +import org.graalvm.polyglot.impl.AbstractPolyglotImpl.AbstractManagementDispatch; /** * An execution event object passed to an execution listener consumer. Execution event instances @@ -57,10 +58,12 @@ */ public final class ExecutionEvent { - private final Object impl; + final AbstractManagementDispatch dispatch; + final Object receiver; - ExecutionEvent(Object impl) { - this.impl = impl; + ExecutionEvent(AbstractManagementDispatch dispatch, Object receiver) { + this.dispatch = dispatch; + this.receiver = receiver; } /** @@ -70,7 +73,7 @@ public final class ExecutionEvent { * @since 19.0 */ public SourceSection getLocation() { - return IMPL.getExecutionEventLocation(impl); + return dispatch.getExecutionEventLocation(receiver); } /** @@ -81,7 +84,7 @@ public SourceSection getLocation() { * @since 19.0 */ public String getRootName() { - return IMPL.getExecutionEventRootName(impl); + return dispatch.getExecutionEventRootName(receiver); } /** @@ -97,7 +100,7 @@ public String getRootName() { * @since 19.0 */ public List getInputValues() { - return IMPL.getExecutionEventInputValues(impl); + return dispatch.getExecutionEventInputValues(receiver); } /** @@ -111,7 +114,7 @@ public List getInputValues() { * @since 19.0 */ public Value getReturnValue() { - return IMPL.getExecutionEventReturnValue(impl); + return dispatch.getExecutionEventReturnValue(receiver); } /** @@ -125,7 +128,7 @@ public Value getReturnValue() { * @since 19.0 */ public PolyglotException getException() { - return IMPL.getExecutionEventException(impl); + return dispatch.getExecutionEventException(receiver); } /** @@ -136,7 +139,7 @@ public PolyglotException getException() { * @since 19.0 */ public boolean isExpression() { - return IMPL.isExecutionEventExpression(impl); + return dispatch.isExecutionEventExpression(receiver); } /** @@ -147,7 +150,7 @@ public boolean isExpression() { * @since 19.0 */ public boolean isStatement() { - return IMPL.isExecutionEventStatement(impl); + return dispatch.isExecutionEventStatement(receiver); } /** @@ -158,7 +161,7 @@ public boolean isStatement() { * @since 19.0 */ public boolean isRoot() { - return IMPL.isExecutionEventRoot(impl); + return dispatch.isExecutionEventRoot(receiver); } /** diff --git a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/management/ExecutionListener.java b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/management/ExecutionListener.java index 03f479474f85..5020eae9a4bf 100644 --- a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/management/ExecutionListener.java +++ b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/management/ExecutionListener.java @@ -47,6 +47,8 @@ import org.graalvm.polyglot.Engine; import org.graalvm.polyglot.PolyglotException; import org.graalvm.polyglot.Source; +import org.graalvm.polyglot.impl.AbstractPolyglotImpl.AbstractManagementDispatch; +import org.graalvm.polyglot.impl.AbstractPolyglotImpl.APIAccess; /** * Execution listeners allow to instrument the execution of guest languages. For example, it is @@ -190,11 +192,13 @@ */ public final class ExecutionListener implements AutoCloseable { - private static final ExecutionListener EMPTY = new ExecutionListener(null); - private final Object impl; + private static final ExecutionListener EMPTY = new ExecutionListener(null, null); + final AbstractManagementDispatch dispatch; + final Object receiver; - private ExecutionListener(Object impl) { - this.impl = impl; + ExecutionListener(AbstractManagementDispatch dispatch, Object receiver) { + this.dispatch = dispatch; + this.receiver = receiver; } /** @@ -211,7 +215,7 @@ private ExecutionListener(Object impl) { * @since 19.0 */ public void close() { - Management.IMPL.closeExecutionListener(impl); + dispatch.closeExecutionListener(receiver); } /** @@ -422,9 +426,9 @@ public Builder collectExceptions(boolean enabled) { * @since 19.0 */ public ExecutionListener attach(Engine engine) { - return new ExecutionListener( - Management.IMPL.attachExecutionListener(Management.IMPL.getPolyglotImpl().getAPIAccess().getReceiver(engine), onEnter, onReturn, expressions, statements, roots, - sourceFilter, rootNameFilter, collectInputValues, collectReturnValues, collectExceptions)); + APIAccess apiAccess = Management.IMPL.getAPIAccess(); + return apiAccess.getDispatch(engine).attachExecutionListener(apiAccess.getReceiver(engine), onEnter, onReturn, expressions, statements, roots, + sourceFilter, rootNameFilter, collectInputValues, collectReturnValues, collectExceptions); } } diff --git a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/management/Management.java b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/management/Management.java index 957ec9ddb2c4..7770320f9cbe 100644 --- a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/management/Management.java +++ b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/management/Management.java @@ -55,15 +55,15 @@ final class Management { private Management() { } - static final AbstractManagementDispatch IMPL = initImpl(); + static final AbstractPolyglotImpl IMPL = initImpl(); - private static AbstractManagementDispatch initImpl() { + private static AbstractPolyglotImpl initImpl() { try { Method method = Engine.class.getDeclaredMethod("getImpl"); method.setAccessible(true); AbstractPolyglotImpl impl = (AbstractPolyglotImpl) method.invoke(null); impl.setMonitoring(new ManagementAccessImpl()); - return impl.getManagementDispatch(); + return impl; } catch (Exception e) { throw new IllegalStateException("Failed to initialize execution listener class.", e); } @@ -72,10 +72,34 @@ private static AbstractManagementDispatch initImpl() { private static final class ManagementAccessImpl extends ManagementAccess { @Override - public ExecutionEvent newExecutionEvent(Object event) { - return new ExecutionEvent(event); + public ExecutionListener newExecutionListener(AbstractManagementDispatch dispatch, Object receiver) { + return new ExecutionListener(dispatch, receiver); } + @Override + public ExecutionEvent newExecutionEvent(AbstractManagementDispatch dispatch, Object event) { + return new ExecutionEvent(dispatch, event); + } + + @Override + public Object getReceiver(ExecutionListener executionListener) { + return executionListener.receiver; + } + + @Override + public AbstractManagementDispatch getDispatch(ExecutionListener executionListener) { + return executionListener.dispatch; + } + + @Override + public Object getReceiver(ExecutionEvent executionEvent) { + return executionEvent.receiver; + } + + @Override + public AbstractManagementDispatch getDispatch(ExecutionEvent executionEvent) { + return executionEvent.dispatch; + } } } diff --git a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/proxy/ProxyObject.java b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/proxy/ProxyObject.java index eeaec2a074b7..3116b4893391 100644 --- a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/proxy/ProxyObject.java +++ b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/proxy/ProxyObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -45,6 +45,7 @@ import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Value; +import org.graalvm.polyglot.HostAccess; /** * Interface to be implemented to mimic guest language objects that contain members. @@ -63,16 +64,16 @@ public interface ProxyObject extends Proxy { Object getMember(String key); /** - * Returns array of member keys. The returned array must be interpreted as having array elements - * using the semantics of {@link Context#asValue(Object)} otherwise and - * {@link IllegalStateException} is thrown. If one of the return values of the array is not a - * {@link String} then a {@link ClassCastException} is thrown. Examples for valid return values - * are: + * Returns an array of member keys. The returned array must be interpreted as having array + * elements using the semantics of {@link Context#asValue(Object)} and taking host access into + * consideration. Otherwise, an {@link IllegalStateException} is thrown. If one of the return + * values of the array is not a {@link String} then a {@link ClassCastException} is thrown. + * Examples for valid return values are: *
      *
    • null for no member keys *
    • {@link ProxyArray} that returns {@link String} values for each array element - *
    • {@link List } with exclusively String elements - *
    • {@link String String[]} + *
    • {@link List } with exclusively String elements ({@link HostAccess} must allowListAccess) + *
    • {@link String String[]} ({@link HostAccess} must allowArrayAccess) *
    • A guest language object representing an array of strings. *
    * Every member key returned by the {@link #getMemberKeys()} method must return diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md new file mode 100644 index 000000000000..b01373c7212c --- /dev/null +++ b/substratevm/CHANGELOG.md @@ -0,0 +1,10 @@ +# Native Image Changelog + +This changelog summarizes major changes to GraalVM Native Image. + +## Version 22.0.0 +* (GR-33930) Decouple HostedOptionParser setup from classpath/modulepath scanning (use ServiceLoader for collecting options). +* (GR-33504) Implement --add-reads for native-image and fix --add-opens error handling. +* (GR-33983) Remove obsolete com.oracle.svm.thirdparty.jline.JLineFeature from substratevm:LIBRARY_SUPPORT. +* (GR-34577) Remove support for outdated JDK versions between 11 and 17. Since JDK versions 12, 13, 14, 15, 16 are no longer supported, there is no need to explicitly check for and allow these versions. + diff --git a/substratevm/ci_includes/gate.hocon b/substratevm/ci_includes/gate.hocon index fe41f3535dbf..4635d21048e2 100644 --- a/substratevm/ci_includes/gate.hocon +++ b/substratevm/ci_includes/gate.hocon @@ -18,56 +18,52 @@ gate-svm-js: { } builds += [ - ${oraclejdk8} ${svm-common-linux-gate} ${gate-svm-js} ${svm-capabilities-base} { + ${labsjdk-ce-17} ${svm-common-linux-gate} ${gate-svm-js} ${svm-capabilities-base} { name: "gate-svm-js" timelimit: "35:00" } - ${oraclejdk8} ${svm-common-darwin-gate} ${gate-svm-js} { + ${labsjdk-ce-17} ${svm-common-darwin-gate} ${gate-svm-js} { name: "gate-svm-darwin-js" } - ${labsjdk-ee-11} ${svm-common-linux-gate} ${linux-deploy} { - name: "gate-svm-build-ee-11" + ${labsjdk-ce-11} ${svm-common-linux-gate} ${linux-deploy} { + name: "gate-svm-build-ce-11" downloads: { - "MUSL_LIBS": { - "name": "musl-libs", + "MUSL_TOOLCHAIN": { + "name": "musl-toolchain", "version": "1.0", "platformspecific": true } } environment : { - MAVEN_REPO_LOCAL : "$BUILD_DIR/.m2" - PATH : "$MUSL_LIBS/bin:$PATH" + # Note that we must add the toolchain to the end of the PATH so that the system gcc still remains the first choice + # for building the rest of GraalVM. The musl toolchain also provides a gcc executable that would shadow the system one + # if it were added at the start of the PATH. + PATH : "$PATH:$MUSL_TOOLCHAIN/bin" } run: [ - ["$MUSL_LIBS/fix_paths.sh"] - ${svm-cmd-gate} ["build,helloworld,test,maven,nativeimagehelp,muslcbuild"] + ${svm-cmd-gate} ["build,helloworld,test,nativeimagehelp,muslcbuild"] ] } - ${labsjdk-ee-11} ${svm-common-linux-gate} ${linux-deploy} { + ${labsjdk-ce-11} ${svm-common-linux-gate} ${linux-deploy} { name: "gate-svm-modules-basic" run: [ ${svm-cmd-gate} ["build,hellomodule,test"] ] } - ${oraclejdk8} ${svm-common-linux-gate} ${eclipse} ${jdt} ${linux-deploy} { + ${labsjdk-ce-17} ${svm-common-linux-gate} ${eclipse} ${jdt} ${linux-deploy} { name: "gate-svm-style-fullbuild" timelimit: "45:00" environment : { - MAVEN_REPO_LOCAL : "$BUILD_DIR/.m2" MX_BUILD_EXPLODED : "true" # test native-image MX_BUILD_EXPLODED compatibility } run: [ - ${svm-cmd-gate} ["style,fullbuild,helloworld,test,svmjunit,maven"] + ${svm-cmd-gate} ["style,fullbuild,helloworld,test,svmjunit"] ] } - ${oraclejdk8} ${svm-common-gate} ${svm-common-windows-oraclejdk8} { + ${labsjdk-ce-17} ${svm-common-gate} ${svm-common-windows-jdk17} { name: "gate-svm-windows-basics" - environment: { - PATH : "$MVN_HOME;$PATH" # workaround until GR-10735 is resolved - MAVEN_REPO_LOCAL : "$BUILD_DIR\.m2" - } run: [ - ${svm-cmd-gate} ["build,helloworld,test,svmjunit,maven"] + ${svm-cmd-gate} ["build,helloworld,test,svmjunit"] ] } ] diff --git a/substratevm/mx.substratevm/macro-junit.properties b/substratevm/mx.substratevm/macro-junit.properties index 8c093a44d0f1..6f802d0e00a0 100644 --- a/substratevm/mx.substratevm/macro-junit.properties +++ b/substratevm/mx.substratevm/macro-junit.properties @@ -2,6 +2,7 @@ ImageName = svmjunit +ImageModulePath = ${.}/junit-support.jar ImageClasspath = ${.}/junit-tool.jar:${.}/junit.jar:${.}/hamcrest.jar Args = -H:Features=com.oracle.svm.junit.JUnitFeature \ diff --git a/substratevm/mx.substratevm/macro-junitcp.properties b/substratevm/mx.substratevm/macro-junitcp.properties new file mode 100644 index 000000000000..3fb002782ec9 --- /dev/null +++ b/substratevm/mx.substratevm/macro-junitcp.properties @@ -0,0 +1,10 @@ +# This file contains support for building a set of junit tests into a native-image + +ImageName = svmjunit + +ImageClasspath = ${.}/junit-support.jar:${.}/junit-tool.jar:${.}/junit.jar:${.}/hamcrest.jar + +Args = -H:Features=com.oracle.svm.junit.JUnitFeature \ + -H:Class=com.oracle.svm.junit.SVMJUnitRunner \ + -H:TestFile=${*} \ + --initialize-at-build-time=org.junit,com.oracle.mxtool.junit.MxJUnitRequest diff --git a/substratevm/mx.substratevm/mx_substratevm.py b/substratevm/mx.substratevm/mx_substratevm.py index 2e5dc90cb77f..f737bd599554 100644 --- a/substratevm/mx.substratevm/mx_substratevm.py +++ b/substratevm/mx.substratevm/mx_substratevm.py @@ -45,6 +45,7 @@ import mx_gate import mx_unittest import mx_sdk_vm +import mx_sdk_vm_impl import mx_javamodules import mx_subst import mx_substratevm_benchmark # pylint: disable=unused-import @@ -115,16 +116,6 @@ def svmbuild_dir(suite=None): return join(suite.dir, 'svmbuild') -def is_musl_gcc_wrapper_on_path(): - mx.logv('Probing if musl-gcc exists on path.') - throwaway_capture = mx.LinesOutputCapture() - try: - ret_code = mx.run(['musl-gcc', '-v'], nonZeroIsFatal=False, out=throwaway_capture, err=throwaway_capture) - return ret_code == 0 - except OSError as _: - return False - - def is_musl_supported(): jdk = mx.get_jdk(tag='default') if mx.is_linux() and mx.get_arch() == "amd64" and mx.get_jdk(tag='default').javaCompliance == '11': @@ -176,6 +167,14 @@ def _run_graalvm_cmd(cmd_args, config, nonZeroIsFatal=True, out=None, err=None, primary_suite_dir = config.primary_suite_dir else: config_args = [] + if not mx_sdk_vm_impl._jlink_libraries(): + config_args += ['--no-jlinking'] + native_images = mx_sdk_vm_impl._parse_cmd_arg('native_images') + if native_images: + config_args += ['--native-images=' + ','.join(native_images)] + components = mx_sdk_vm_impl._components_include_list() + if components: + config_args += ['--components=' + ','.join(c.name for c in components)] dynamic_imports = [x for x, _ in mx.get_dynamic_imports()] if dynamic_imports: config_args += ['--dynamicimports', ','.join(dynamic_imports)] @@ -234,10 +233,7 @@ def vm_executable_path(executable, config=None): def run_musl_basic_tests(): if is_musl_supported(): - if is_musl_gcc_wrapper_on_path(): - helloworld(['--output-path', svmbuild_dir(), '--static', '--libc=musl']) - else: - mx.abort('Attempted to run musl tests without a musl-gcc wrapper.') + helloworld(['--output-path', svmbuild_dir(), '--static', '--libc=musl']) @contextmanager @@ -434,7 +430,11 @@ def native_unittests_task(): '-H:AdditionalSecurityServiceTypes=com.oracle.svm.test.SecurityServiceTest$JCACompliantNoOpService' ] - native_unittest(['--build-args', _native_unittest_features] + additional_build_args) + if svm_java_compliance() == '17': + if mx.is_windows(): + mx_unittest.add_global_ignore_glob('com.oracle.svm.test.SecurityServiceTest') + + native_unittest(['--builder-on-modulepath', '--build-args', _native_unittest_features] + additional_build_args) def javac_image_command(javac_path): @@ -442,7 +442,7 @@ def javac_image_command(javac_path): join(mx_compiler.jdk.home, "jre", "lib", "rt.jar")] -def _native_junit(native_image, unittest_args, build_args=None, run_args=None, blacklist=None, whitelist=None, preserve_image=False): +def _native_junit(native_image, unittest_args, build_args=None, run_args=None, blacklist=None, whitelist=None, preserve_image=False, builder_on_modulepath=False): build_args = build_args or [] javaProperties = {} for dist in suite.dists: @@ -469,7 +469,8 @@ def dummy_harness(test_deps, vm_launcher, vm_args): with open(unittest_file, 'r') as f: mx.log('Building junit image for matching: ' + ' '.join(l.rstrip() for l in f)) extra_image_args = mx.get_runtime_jvm_args(unittest_deps, jdk=mx_compiler.jdk, exclude_names=['substratevm:LIBRARY_SUPPORT']) - unittest_image = native_image(['-ea', '-esa'] + build_args + extra_image_args + ['--macro:junit=' + unittest_file, '-H:Path=' + junit_test_dir]) + macro_junit = '--macro:junit' + ('' if builder_on_modulepath else 'cp') + unittest_image = native_image(['-ea', '-esa'] + build_args + extra_image_args + [macro_junit + '=' + unittest_file, '-H:Path=' + junit_test_dir]) mx.log('Running: ' + ' '.join(map(pipes.quote, [unittest_image] + run_args))) mx.run([unittest_image] + run_args) finally: @@ -492,13 +493,14 @@ def unmask(args): def _native_unittest(native_image, cmdline_args): parser = ArgumentParser(prog='mx native-unittest', description='Run unittests as native image.') - all_args = ['--build-args', '--run-args', '--blacklist', '--whitelist', '-p', '--preserve-image'] + all_args = ['--build-args', '--run-args', '--blacklist', '--whitelist', '-p', '--preserve-image', '--builder-on-modulepath'] cmdline_args = [_mask(arg, all_args) for arg in cmdline_args] parser.add_argument(all_args[0], metavar='ARG', nargs='*', default=[]) parser.add_argument(all_args[1], metavar='ARG', nargs='*', default=[]) parser.add_argument('--blacklist', help='run all testcases not specified in ', metavar='') parser.add_argument('--whitelist', help='run testcases specified in only', metavar='') parser.add_argument('-p', '--preserve-image', help='do not delete the generated native image', action='store_true') + parser.add_argument('--builder-on-modulepath', help='perform image build with builder on module-path', action='store_true') parser.add_argument('unittest_args', metavar='TEST_ARG', nargs='*') pargs = parser.parse_args(cmdline_args) @@ -519,7 +521,11 @@ def _native_unittest(native_image, cmdline_args): mx.log('warning: could not read blacklist: ' + blacklist) unittest_args = unmask(pargs.unittest_args) if unmask(pargs.unittest_args) else ['com.oracle.svm.test', 'com.oracle.svm.configure.test'] - _native_junit(native_image, unittest_args, unmask(pargs.build_args), unmask(pargs.run_args), blacklist, whitelist, pargs.preserve_image) + builder_on_modulepath = pargs.builder_on_modulepath + if builder_on_modulepath and svm_java8(): + mx.log('On Java 8, unittests cannot be built with imagebuilder on module-path. Reverting to imagebuilder on classpath.') + builder_on_modulepath = False + _native_junit(native_image, unittest_args, unmask(pargs.build_args), unmask(pargs.run_args), blacklist, whitelist, pargs.preserve_image, builder_on_modulepath) def js_image_test(binary, bench_location, name, warmup_iterations, iterations, timeout=None, bin_args=None): @@ -761,6 +767,7 @@ def native_image_context_run(func, func_args=None, config=None, build_if_missing 'substratevm:SVM', 'substratevm:OBJECTFILE', 'substratevm:POINTSTO', + 'substratevm:NATIVE_IMAGE_BASE', ], support_distributions=['substratevm:SVM_GRAALVM_SUPPORT'], stability="earlyadopter", @@ -928,11 +935,24 @@ def _native_image_launcher_extra_jvm_args(): license_files=[], third_party_license_files=[], dependencies=['SubstrateVM'], - jar_distributions=['mx:JUNIT_TOOL', 'mx:JUNIT', 'mx:HAMCREST'], + jar_distributions=['substratevm:JUNIT_SUPPORT', 'mx:JUNIT_TOOL', 'mx:JUNIT', 'mx:HAMCREST'], support_distributions=['substratevm:NATIVE_IMAGE_JUNIT_SUPPORT'], jlink=False, )) +mx_sdk_vm.register_graalvm_component(mx_sdk_vm.GraalVMSvmMacro( + suite=suite, + name='Native Image JUnit with image-builder on classpath', + short_name='njucp', + dir_name='junitcp', + license_files=[], + third_party_license_files=[], + dependencies=['SubstrateVM'], + jar_distributions=['substratevm:JUNIT_SUPPORT', 'mx:JUNIT_TOOL', 'mx:JUNIT', 'mx:HAMCREST'], + support_distributions=['substratevm:NATIVE_IMAGE_JUNITCP_SUPPORT'], + jlink=False, +)) + jar_distributions = [ 'substratevm:GRAAL_HOTSPOT_LIBRARY', 'compiler:GRAAL_TRUFFLE_COMPILER_LIBGRAAL', @@ -1004,6 +1024,9 @@ def _native_image_configure_extra_jvm_args(): ) ], jlink=False, + installable_id='native-image', + installable=True, + priority=10, )) @@ -1541,7 +1564,5 @@ def javac_image(args): doc_string = "Runs a musl based Hello World static native-image with custom build arguments." @mx.command(suite.name, command_name='muslhelloworld', usage_msg='[options]', doc_function=lambda: doc_string) def musl_helloworld(args, config=None): - if not is_musl_gcc_wrapper_on_path(): - mx.abort('musl-gcc wrapper not detected on path. Cannot run musl helloworld. Please consult substratevm/StaticImages.md') final_args = ['--static', '--libc=musl'] + args run_helloworld_command(final_args, config, 'muslhelloworld') diff --git a/substratevm/mx.substratevm/mx_substratevm_benchmark.py b/substratevm/mx.substratevm/mx_substratevm_benchmark.py index 0db79674e2a4..226ada438e2a 100644 --- a/substratevm/mx.substratevm/mx_substratevm_benchmark.py +++ b/substratevm/mx.substratevm/mx_substratevm_benchmark.py @@ -61,6 +61,12 @@ def list_jars(path): _RENAISSANCE_EXTRA_IMAGE_BUILD_ARGS = { + 'als' : [ + '--allow-incomplete-classpath', + '--report-unsupported-elements-at-runtime', + '--initialize-at-build-time=org.slf4j,org.apache.log4j', # mis-initialized from netty + '--initialize-at-run-time=io.netty.channel.unix.IovArray,io.netty.channel.epoll.EpollEventLoop,io.netty.channel.unix.Errors,io.netty.channel.unix.Socket,io.netty.channel.unix.Limits' + ], 'chi-square' : [ '--allow-incomplete-classpath', '--report-unsupported-elements-at-runtime', @@ -91,48 +97,114 @@ def list_jars(path): } _renaissance_config = { - "akka-uct" : ("actors", 11), # GR-17994 - "reactors" : ("actors", 11), - "scala-kmeans" : ("scala-stdlib", 12), - "mnemonics" : ("jdk-streams", 12), - "par-mnemonics" : ("jdk-streams", 12), - "rx-scrabble" : ("rx", 12), - "als" : ("apache-spark", 11), - "chi-square" : ("apache-spark", 11), - "db-shootout" : ("database", 11), # GR-17975, GR-17943 (with --report-unsupported-elements-at-runtime) - "dec-tree" : ("apache-spark", 11), - "dotty" : ("scala-dotty", 12), # GR-17985 - "finagle-chirper" : ("twitter-finagle", 11), - "finagle-http" : ("twitter-finagle", 11), - "fj-kmeans" : ("jdk-concurrent", 12), - "future-genetic" : ("jdk-concurrent", 12), # GR-17988 - "gauss-mix" : ("apache-spark", 11), - "log-regression" : ("apache-spark", 11), - "movie-lens" : ("apache-spark", 11), - "naive-bayes" : ("apache-spark", 11), - "neo4j-analytics" : ("neo4j", 11), - "page-rank" : ("apache-spark", 11), - "philosophers" : ("scala-stm", 12), - "scala-stm-bench7" : ("scala-stm", 12), - "scrabble" : ("jdk-streams", 12) -} - -# breeze jar is replaced with a patched jar because of IncompatibleClassChange errors due to a bug in the Scala compiler. -_renaissance_additional_lib = { - 'apache-spark' : ['SPARK_BREEZE_PATCHED'] -} - -_renaissance_exclude_lib = { - 'apache-spark' : ['breeze_2.11-0.11.2.jar'] + "akka-uct": { + "group": "actors-akka", + "legacy-group": "actors", + "requires-recompiled-harness": ["0.9.0", "0.10.0", "0.11.0"] + }, + "reactors": { + "group": "actors-reactors", + "legacy-group": "actors", + "requires-recompiled-harness": True + }, + "scala-kmeans": { + "group": "scala-stdlib" + }, + "scala-doku": { + "group": "scala-sat" + }, + "mnemonics": { + "group": "jdk-streams" + }, + "par-mnemonics": { + "group": "jdk-streams" + }, + "rx-scrabble": { + "group": "rx" + }, + "als": { + "group": "apache-spark", + "requires-recompiled-harness": True + }, + "chi-square": { + "group": "apache-spark", + "requires-recompiled-harness": True + }, + "db-shootout": { # GR-17975, GR-17943 (with --report-unsupported-elements-at-runtime) + "group": "database", + "requires-recompiled-harness": ["0.9.0", "0.10.0", "0.11.0"] + }, + "dec-tree": { + "group": "apache-spark", + "requires-recompiled-harness": True + }, + "dotty": { + "group": "scala-dotty" + }, + "finagle-chirper": { + "group": "twitter-finagle", + "requires-recompiled-harness": True + }, + "finagle-http": { + "group": "twitter-finagle", + "requires-recompiled-harness": True + }, + "fj-kmeans": { + "group": "jdk-concurrent" + }, + "future-genetic": { + "group": "jdk-concurrent" + }, + "gauss-mix": { + "group": "apache-spark", + "requires-recompiled-harness": True + }, + "log-regression": { + "group": "apache-spark", + "requires-recompiled-harness": True + }, + "movie-lens": { + "group": "apache-spark", + "requires-recompiled-harness": True + }, + "naive-bayes": { + "group": "apache-spark", + "requires-recompiled-harness": True + }, + "page-rank": { + "group": "apache-spark", + "requires-recompiled-harness": True + }, + "neo4j-analytics": { + "group": "neo4j", + "requires-recompiled-harness": True + }, + "philosophers": { + "group": "scala-stm", + "requires-recompiled-harness": ["0.12.0", "0.13.0"] + }, + "scala-stm-bench7": { + "group": "scala-stm", + "requires-recompiled-harness": ["0.12.0", "0.13.0"] + }, + "scrabble": { + "group": "jdk-streams" + } } -def benchmark_group(benchmark): - return _renaissance_config[benchmark][0] +def benchmark_group(benchmark, suite_version): + if suite_version in ["0.9.0", "0.10.0", "0.11.0"]: + return _renaissance_config[benchmark].get("legacy-group", _renaissance_config[benchmark]["group"]) + else: + return _renaissance_config[benchmark]["group"] -def benchmark_scalaversion(benchmark): - return _renaissance_config[benchmark][1] +def requires_recompiled_harness(benchmark, suite_version): + requires_harness = _renaissance_config[benchmark].get("requires-recompiled-harness", False) + if isinstance(requires_harness, list): + return suite_version in requires_harness + return requires_harness class RenaissanceNativeImageBenchmarkSuite(mx_java_benchmarks.RenaissanceBenchmarkSuite, mx_sdk_benchmark.NativeImageBenchmarkMixin): #pylint: disable=too-many-ancestors @@ -153,7 +225,7 @@ def benchSuiteName(self, bmSuiteArgs=None): return 'renaissance' def renaissance_harness_lib_name(self): - version_to_run = super(RenaissanceNativeImageBenchmarkSuite, self).version() + version_to_run = self.version() version_end_index = str(version_to_run).rindex('.') return 'RENAISSANCE_HARNESS_v' + str(version_to_run)[0:version_end_index] @@ -166,7 +238,7 @@ def harness_path(self): # Before supporting new Renaissance versions, we must cross-compile Renaissance harness project # with scala 11 for benchmarks compiled with this version of Scala. def availableSuiteVersions(self): - return ["0.9.0", "0.10.0", "0.11.0"] + return ["0.9.0", "0.10.0", "0.11.0", "0.12.0", "0.13.0"] def renaissance_unpacked(self): return extract_archive(self.renaissancePath(), 'renaissance.extracted') @@ -216,9 +288,10 @@ def successPatterns(self): _successful_stage_pattern ] - def create_classpath(self, benchArg): - harness_project = RenaissanceNativeImageBenchmarkSuite.RenaissanceProject('harness', benchmark_scalaversion(benchArg), self) - group_project = RenaissanceNativeImageBenchmarkSuite.RenaissanceProject(benchmark_group(benchArg), benchmark_scalaversion(benchArg), self, harness_project) + def create_classpath(self, benchmarkName): + custom_harness = requires_recompiled_harness(benchmarkName, self.version()) + harness_project = RenaissanceNativeImageBenchmarkSuite.RenaissanceProject('harness', custom_harness, self) + group_project = RenaissanceNativeImageBenchmarkSuite.RenaissanceProject(benchmark_group(benchmarkName, self.version()), custom_harness, self, harness_project) return ':'.join([mx.classpath(harness_project), mx.classpath(group_project)]) class RenaissanceDependency(mx.ClasspathDependency): @@ -233,10 +306,10 @@ def _walk_deps_visit_edges(self, *args, **kwargs): pass class RenaissanceProject(mx.ClasspathDependency): - def __init__(self, group, scala_version=12, renaissance_suite=None, dep_project=None): # pylint: disable=super-init-not-called + def __init__(self, group, requires_recompiled_harness, renaissance_suite, dep_project=None): # pylint: disable=super-init-not-called mx.Dependency.__init__(self, _suite, group, None) self.suite = renaissance_suite - self.deps = self.collect_group_dependencies(group, scala_version) + self.deps = self.collect_group_dependencies(group, requires_recompiled_harness) if dep_project is not None: self.deps.append(dep_project) @@ -251,24 +324,25 @@ def get_dependencies(self, path, group): deps = [] for jar in list_jars(path): deps.append(RenaissanceNativeImageBenchmarkSuite.RenaissanceDependency(os.path.basename(jar), mx.join(path, jar))) - if group in _renaissance_exclude_lib: - for lib in _renaissance_exclude_lib[group]: - lib_dep = RenaissanceNativeImageBenchmarkSuite.RenaissanceDependency(lib, mx.join(path, lib)) + + if self.suite.version() in ["0.9.0", "0.10.0", "0.11.0"]: + if group == 'apache-spark': + # breeze jar is replaced with a patched jar because of IncompatibleClassChange errors due to a bug in the Scala compiler + invalid_bytecode_jar = 'breeze_2.11-0.11.2.jar' + lib_dep = RenaissanceNativeImageBenchmarkSuite.RenaissanceDependency(invalid_bytecode_jar, mx.join(path, invalid_bytecode_jar)) if lib_dep in deps: deps.remove(lib_dep) - if group in _renaissance_additional_lib: - for lib in _renaissance_additional_lib[group]: - lib_path = RenaissanceNativeImageBenchmarkSuite.renaissance_additional_lib(self.suite, lib) + lib_path = RenaissanceNativeImageBenchmarkSuite.renaissance_additional_lib(self.suite, 'SPARK_BREEZE_PATCHED') deps.append(RenaissanceNativeImageBenchmarkSuite.RenaissanceDependency(os.path.basename(lib_path), lib_path)) return deps - def collect_group_dependencies(self, group, scala_version): + def collect_group_dependencies(self, group, requires_recompiled_harness): if group == 'harness': - if scala_version == 12: + if requires_recompiled_harness: + path = RenaissanceNativeImageBenchmarkSuite.harness_path(self.suite) + else: unpacked_renaissance = RenaissanceNativeImageBenchmarkSuite.renaissance_unpacked(self.suite) path = mx.join(unpacked_renaissance, 'renaissance-harness') - else: - path = RenaissanceNativeImageBenchmarkSuite.harness_path(self.suite) else: unpacked_renaissance = RenaissanceNativeImageBenchmarkSuite.renaissance_unpacked(self.suite) path = mx.join(unpacked_renaissance, 'benchmarks', group) diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 31e8543fad08..9b458ff395ee 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -1,8 +1,8 @@ # pylint: disable=line-too-long suite = { - "mxversion": "5.308.1", + "mxversion": "5.310.0", "name": "substratevm", - "version" : "21.3.0", + "version" : "22.0.0", "release" : False, "url" : "https://github.com/oracle/graal/tree/master/substratevm", @@ -53,6 +53,16 @@ "sha1" : "8d402c1e7c972badfcffdd6c64ed4e791b0dea02", "packedResource": True, }, + "RENAISSANCE_HARNESS_v0.12" : { + "urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/renaissance/renaissance-harness_v0.12.0.tar.gz"], + "sha1" : "84592bedd6f0afa842aadb8813d395317b1fa385", + "packedResource": True, + }, + "RENAISSANCE_HARNESS_v0.13" : { + "urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/renaissance/renaissance-harness_v0.13.0.tar.gz"], + "sha1" : "8edc1db5c7ea977e2a9c037b5324bb4cbee40082", + "packedResource": True, + }, "DACAPO_SVM" : { "urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/dacapo-9.12-native-image.jar"], "sha1" : "5d534f0b7aa9124d9797a180688468d2f126039a", @@ -70,36 +80,36 @@ }, }, "LLVM_WRAPPER_SHADOWED": { - "sha1" : "f2d365a8d432d6b2127acda19c5d3418126db9b0", - "sourceSha1" : "0801daf22b189bbd9d515614a2b79c92af225d56", + "sha1" : "55eb45a7ae133f98df8d61e821af0d373ae027e8", + "sourceSha1" : "f4841e1e2426333094df5c43751e6148a550e506", "dependencies" : ["JAVACPP_SHADOWED"], - "urlbase": "https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/native-image", - "urls": ["{urlbase}/llvm-shadowed-9.0.0-1.5.2.jar"], - "sourceUrls": ["{urlbase}/llvm-shadowed-9.0.0-1.5.2-sources.jar"], + "urlbase": "http://mos.bplaced.net/llvm", + "urls": ["{urlbase}/llvm-shadowed-12.0.1-1.5.6.jar"], + "sourceUrls": ["{urlbase}/llvm-shadowed-12.0.1-1.5.6-sources.jar"], "license" : "GPLv2-CPE", "moduleName" : "com.oracle.svm.shadowed.org.bytedeco.llvm" }, "JAVACPP_SHADOWED": { - "sha1" : "212aaddcd73448c7b6da781fb6cde934c667dc2c", - "sourceSha1" : "3e9cfc02750ba8ea3babc1b8546a50ec36b849a2", - "urlbase": "https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/native-image", - "urls": ["{urlbase}/javacpp-shadowed-1.5.2.jar"], - "sourceUrls": ["{urlbase}/javacpp-shadowed-1.5.2-sources.jar"], + "sha1" : "761db712863a8ac533ef4e28ddcfdd49bc71955c", + "sourceSha1" : "da52e2a8b39415f279e388a0e68d77817d471ae3", + "urlbase": "http://mos.bplaced.net/llvm", + "urls": ["{urlbase}/javacpp-shadowed-1.5.6.jar"], + "sourceUrls": ["{urlbase}/javacpp-shadowed-1.5.6-sources.jar"], "license" : "GPLv2-CPE", "moduleName" : "com.oracle.svm.shadowed.org.bytedeco.javacpp" }, "LLVM_PLATFORM_SPECIFIC_SHADOWED": { - "urlbase": "https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/native-image", + "urlbase": "http://mos.bplaced.net/llvm", "os_arch": { "linux": { "amd64": { - "sha1": "53acc3692e0f67f3b4a4e5fa5b4a5a1de1aa7947", - "urls": ["{urlbase}/llvm-shadowed-9.0.0-1.5.2-linux-x86_64.jar"], + "sha1": "45b8746a30bc774e912eb6c5aa83740608107012", + "urls": ["{urlbase}/llvm-shadowed-12.0.1-1.5.6-linux-x86_64.jar"], "moduleName" : "com.oracle.svm.shadowed.org.bytedeco.llvm.linux.x86_64" }, "aarch64": { - "sha1": "49b2bff3ab0ecea436bd0f8ed64af28e5bdbd03a", - "urls": ["{urlbase}/llvm-shadowed-9.0.0-1.5.2-linux-arm64.jar"], + "sha1": "b7d973cf254ee2226296ed39025391b9aae41dd6", + "urls": ["{urlbase}/llvm-shadowed-12.0.1-1.5.6-linux-arm64.jar"], "moduleName" : "com.oracle.svm.shadowed.org.bytedeco.llvm.linux.arm64" }, "": { @@ -108,8 +118,8 @@ }, "darwin": { "amd64": { - "sha1": "d1082bfd227b8f084682a2cd3b06e36f5d046e5e", - "urls": ["{urlbase}/llvm-shadowed-9.0.0-1.5.2-macosx-x86_64.jar"], + "sha1": "98f3c9b047eff0890b638a6f81c1f9697db658f2", + "urls": ["{urlbase}/llvm-shadowed-12.0.1-1.5.6-macosx-x86_64.jar"], "moduleName" : "com.oracle.svm.shadowed.org.bytedeco.llvm.macosx.x86_64" }, }, @@ -137,6 +147,19 @@ "checkstyle": "com.oracle.svm.core", "workingSets": "SVM", }, + "com.oracle.svm.common": { + "subDir": "src", + "sourceDirs": ["src"], + "dependencies": [ + "com.oracle.svm.util" + ], + "javaCompliance": "8+", + "annotationProcessors": [ + "compiler:GRAAL_PROCESSOR", + ], + "checkstyle": "com.oracle.svm.core", + "workingSets": "SVM", + }, "com.oracle.svm.util.jdk11": { "subDir": "src", "sourceDirs": ["src"], @@ -164,7 +187,7 @@ "headers", ], "dependencies": [ - "com.oracle.svm.util", + "com.oracle.svm.common", ], "javaCompliance": "8+", "checkstyleVersion" : "8.36.1", @@ -220,61 +243,13 @@ "workingSets": "SVM", }, - "com.oracle.svm.core.jdk14": { - "subDir": "src", - "sourceDirs": ["src"], - "dependencies": ["com.oracle.svm.core"], - "requiresConcealed" : { - "java.base" : [ - "jdk.internal.access.foreign", - ], - }, - "javaCompliance": "14+", - "checkstyle": "com.oracle.svm.core", - "workingSets": "SVM", - }, - - "com.oracle.svm.core.jdk15": { - "subDir": "src", - "sourceDirs": ["src"], - "dependencies": [ - "com.oracle.svm.core", - "com.oracle.svm.core.jdk11" - ], - "requiresConcealed" : { - "java.base" : [ - "jdk.internal.loader", - "jdk.internal.misc", - "sun.invoke.util", - ], - }, - "javaCompliance": "15+", - "checkstyle": "com.oracle.svm.core", - "workingSets": "SVM", - }, - - "com.oracle.svm.core.jdk16": { - "subDir": "src", - "sourceDirs": ["src"], - "dependencies": ["com.oracle.svm.core"], - "requiresConcealed" : { - "java.base" : [ - "jdk.internal.loader", - "jdk.internal.misc", - "sun.invoke.util", - ], - }, - "javaCompliance": "16+", - "checkstyle": "com.oracle.svm.core", - "workingSets": "SVM", - }, - "com.oracle.svm.core.jdk17": { "subDir": "src", "sourceDirs": ["src"], - "dependencies": ["com.oracle.svm.core"], + "dependencies": ["com.oracle.svm.core.jdk11"], "requiresConcealed" : { "java.base" : [ + "jdk.internal.access.foreign", "jdk.internal.loader", "jdk.internal.misc", "jdk.internal.platform", @@ -380,7 +355,7 @@ "subDir": "src", "sourceDirs": ["src"], "dependencies": [ - "com.oracle.svm.util", + "com.oracle.svm.common", ], "checkstyle": "com.oracle.graal.pointsto", "javaCompliance": "8+", @@ -398,8 +373,11 @@ "com.oracle.svm.core", "com.oracle.graal.pointsto", ], + "requiresConcealed": { + "java.base": ["sun.util.resources"], + }, "javaCompliance": "8+", - "checkstyleVersion" : "8.36.1", + "checkstyleVersion": "8.36.1", "annotationProcessors": [ "compiler:GRAAL_PROCESSOR", ], @@ -431,7 +409,11 @@ "requires" : ["java.instrument"], "requiresConcealed" : { "jdk.internal.vm.ci": ["jdk.vm.ci.meta"], - "java.base" : ["jdk.internal.module"], + "java.base": [ + "jdk.internal.module", + "sun.text.spi", + "sun.util.resources" + ], }, "javaCompliance": "11+", "checkstyle" : "com.oracle.svm.hosted", @@ -441,7 +423,7 @@ ], "workingSets": "SVM", }, - "com.oracle.svm.hosted.jdk14": { + "com.oracle.svm.hosted.jdk17": { "subDir": "src", "sourceDirs": ["src"], "dependencies": [ @@ -453,7 +435,7 @@ "jdk.internal.vm.ci" : ["jdk.vm.ci.meta"], }, - "javaCompliance": "14+", + "javaCompliance": "17+", "annotationProcessors": [ "compiler:GRAAL_PROCESSOR", ], @@ -645,7 +627,10 @@ "com.oracle.svm.junit": { "subDir": "src", - "sourceDirs": ["src"], + "sourceDirs": [ + "src", + "resources", + ], "dependencies": [ "com.oracle.svm.reflect", "mx:JUNIT_TOOL", @@ -943,6 +928,7 @@ "annotationProcessors": [ "compiler:GRAAL_PROCESSOR", ], + "defaultBuild": False, }, "com.oracle.svm.configure": { @@ -1044,7 +1030,7 @@ "annotationProcessors": [ "compiler:GRAAL_PROCESSOR", ], - "javaCompliance": "1.8", + "javaCompliance": "8+", }, }, @@ -1061,13 +1047,10 @@ "com.oracle.svm.hosted", "com.oracle.svm.hosted.jdk8", "com.oracle.svm.hosted.jdk11", - "com.oracle.svm.hosted.jdk14", + "com.oracle.svm.hosted.jdk17", "com.oracle.svm.core", "com.oracle.svm.core.jdk8", "com.oracle.svm.core.jdk11", - "com.oracle.svm.core.jdk14", - "com.oracle.svm.core.jdk15", - "com.oracle.svm.core.jdk16", "com.oracle.svm.core.jdk17", "com.oracle.svm.core.graal.amd64", "com.oracle.svm.core.graal.aarch64", @@ -1088,6 +1071,7 @@ "OBJECTFILE", "POINTSTO", "compiler:GRAAL", + "NATIVE_IMAGE_BASE", ], "moduleInfo" : { "name" : "org.graalvm.nativeimage.builder", @@ -1097,16 +1081,19 @@ "com.oracle.svm.core.snippets", # Uses of com.oracle.svm.core.snippets.KnownIntrinsics "com.oracle.svm.core", # Uses of com.oracle.svm.core.TypeResult "com.oracle.svm.core.util", # Uses of com.oracle.svm.core.util.VMError + "com.oracle.svm.jfr", # Uses of com.oracle.svm.jfr.JfrEnabled "com.oracle.svm.hosted to java.base", "com.oracle.svm.hosted.agent to java.instrument", "com.oracle.svm.truffle.api to org.graalvm.truffle", - "* to jdk.internal.vm.compiler,org.graalvm.nativeimage.driver,org.graalvm.nativeimage.configure,org.graalvm.nativeimage.librarysupport,org.graalvm.nativeimage.llvm,org.graalvm.nativeimage.agent.jvmtibase,org.graalvm.nativeimage.agent.tracing,org.graalvm.nativeimage.agent.diagnostics,com.oracle.svm.svm_enterprise", + "* to org.graalvm.nativeimage.base,jdk.internal.vm.compiler,org.graalvm.nativeimage.driver,org.graalvm.nativeimage.configure,org.graalvm.nativeimage.librarysupport,org.graalvm.nativeimage.junitsupport,org.graalvm.nativeimage.llvm,org.graalvm.nativeimage.agent.jvmtibase,org.graalvm.nativeimage.agent.tracing,org.graalvm.nativeimage.agent.diagnostics,com.oracle.svm.svm_enterprise", ], "opens" : [ + "com.oracle.svm.core to jdk.internal.vm.compiler", "com.oracle.svm.core.nodes to jdk.internal.vm.compiler", "com.oracle.svm.core.graal.nodes to jdk.internal.vm.compiler", "com.oracle.svm.core.graal.snippets to jdk.internal.vm.compiler", "com.oracle.svm.hosted.fieldfolding to jdk.internal.vm.compiler", + "com.oracle.svm.reflect.hosted to jdk.internal.vm.compiler", ], "requires": [ "java.management", @@ -1121,6 +1108,7 @@ ], "uses" : [ "org.graalvm.nativeimage.Platform", + "org.graalvm.compiler.options.OptionDescriptors", "com.oracle.truffle.api.TruffleLanguage.Provider", "com.oracle.truffle.api.instrumentation.TruffleInstrument.Provider", "com.oracle.svm.hosted.agent.NativeImageBytecodeInstrumentationAgentExtension", @@ -1152,6 +1140,9 @@ "sun.util.resources", "sun.invoke.util", ], + "java.management": [ + "sun.management", + ], "java.xml.crypto": [ "org.jcp.xml.dsig.internal.dom", ], @@ -1188,11 +1179,6 @@ "com.oracle.svm.jvmtiagentbase", "com.oracle.svm.jvmtiagentbase.jvmti", ], - "requires" : [ - "static com.oracle.mxtool.junit", - "static junit", - "static hamcrest", - ], }, }, @@ -1200,27 +1186,43 @@ "subDir": "src", "description" : "SubstrateVM basic library-support components", "dependencies": [ - "com.oracle.svm.junit", "com.oracle.svm.polyglot", "com.oracle.svm.thirdparty", ], "distDependencies": [ "sdk:GRAAL_SDK", "SVM", - "OBJECTFILE", + ], + "moduleInfo" : { + "name" : "org.graalvm.nativeimage.librarysupport", + "exports" : [ + "* to org.graalvm.nativeimage.builder", + ], + }, + }, + + "JUNIT_SUPPORT": { + "subDir": "src", + "description" : "SubstrateVM suppoprt for building JUnit test into image", + "dependencies": [ + "com.oracle.svm.junit", + ], + "distDependencies": [ + "sdk:GRAAL_SDK", + "SVM", "compiler:GRAAL", "mx:JUNIT_TOOL", ], "moduleInfo" : { - "name" : "org.graalvm.nativeimage.librarysupport", + "name" : "org.graalvm.nativeimage.junitsupport", + "exports" : [ + "* to org.graalvm.nativeimage.builder,org.graalvm.nativeimage.base,org.graalvm.nativeimage.pointsto" + ], "requires" : [ "static com.oracle.mxtool.junit", "static junit", "static hamcrest", - ], - "exports" : [ - "* to org.graalvm.nativeimage.builder", - ], + ] }, }, @@ -1265,6 +1267,7 @@ "distDependencies": [ "SVM", ], + "defaultBuild": False, }, # @@ -1318,9 +1321,6 @@ "org.graalvm.nativeimage.builder", "java.management", "jdk.management", - "static com.oracle.mxtool.junit", - "static junit", - "static hamcrest", ], }, }, @@ -1343,11 +1343,6 @@ "exports" : [ "com.oracle.svm.agent", ], - "requires" : [ - "static com.oracle.mxtool.junit", - "static junit", - "static hamcrest", - ], "requiresConcealed" : { "jdk.internal.vm.ci" : [ "jdk.vm.ci.meta", @@ -1372,11 +1367,6 @@ "exports" : [ "com.oracle.svm.diagnosticsagent", ], - "requires" : [ - "static com.oracle.mxtool.junit", - "static junit", - "static hamcrest", - ], }, }, @@ -1397,14 +1387,29 @@ "* to org.graalvm.nativeimage.agent.tracing", "com.oracle.svm.configure", ], - "requires" : [ - "static com.oracle.mxtool.junit", - "static junit", - "static hamcrest", - ], }, }, + "NATIVE_IMAGE_BASE": { + "subDir": "src", + "description" : "Native Image base that can be shared by native image building and pointsto.", + "dependencies": [ + "com.oracle.svm.common", + "com.oracle.svm.util", + ], + "distDependencies": [ + "compiler:GRAAL", + ], + "exclude": [ + ], + "moduleInfo" : { + "name" : "org.graalvm.nativeimage.base", + "exports" : [ + "com.oracle.svm.util", + "com.oracle.svm.common.option", + ], + } + }, "POINTSTO": { "subDir": "src", @@ -1415,13 +1420,13 @@ ], "distDependencies": [ "compiler:GRAAL", + "NATIVE_IMAGE_BASE", ], "exclude": [ ], "moduleInfo" : { "name" : "org.graalvm.nativeimage.pointsto", "exports" : [ - "com.oracle.svm.util", "com.oracle.graal.pointsto", "com.oracle.graal.pointsto.api", "com.oracle.graal.pointsto.reports", @@ -1572,6 +1577,14 @@ }, }, + "NATIVE_IMAGE_JUNITCP_SUPPORT" : { + "native" : True, + "description" : "Native-image based junit testing support but with running image-builder on classpath", + "layout" : { + "native-image.properties" : "file:mx.substratevm/macro-junitcp.properties", + }, + }, + "SVM_LLVM" : { "subDir" : "src", "description" : "LLVM backend for Native Image", @@ -1590,7 +1603,7 @@ "moduleInfo" : { "name" : "org.graalvm.nativeimage.llvm", "exports" : [ - "* to org.graalvm.nativeimage.builder", + "* to org.graalvm.nativeimage.builder,org.graalvm.nativeimage.base", ], }, "maven" : False, diff --git a/substratevm/mx.substratevm/testhello.py b/substratevm/mx.substratevm/testhello.py index 32346d942bd3..59a33639eb62 100644 --- a/substratevm/mx.substratevm/testhello.py +++ b/substratevm/mx.substratevm/testhello.py @@ -170,10 +170,21 @@ def test(): execute("set pagination off") # enable pretty printing of structures execute("set print pretty on") + + # Print DefaultGreeter and check the modifiers of its methods and fields + exec_string = execute("ptype 'hello.Hello$DefaultGreeter'") + rexp = [r"type = class hello\.Hello\$DefaultGreeter : public hello\.Hello\$Greeter {", + r"%spublic:"%spaces_pattern, + r"%svoid greet\(\);"%spaces_pattern, + r"%sint hashCode\(\);"%spaces_pattern, + r"}"] + checker = Checker("ptype 'hello.Hello$DefaultGreeter'", rexp) + checker.check(exec_string) + # set a break point at hello.Hello::main - # expect "Breakpoint 1 at 0x[0-9a-f]+: file hello.Hello.java, line 70." + # expect "Breakpoint 1 at 0x[0-9a-f]+: file hello.Hello.java, line 76." exec_string = execute("break hello.Hello::main") - rexp = r"Breakpoint 1 at %s: file hello/Hello\.java, line 70\."%address_pattern + rexp = r"Breakpoint 1 at %s: file hello/Hello\.java, line 76\."%address_pattern checker = Checker('break main', rexp) checker.check(exec_string) @@ -182,17 +193,17 @@ def test(): execute("delete breakpoints") # list the line at the breakpoint - # expect "70 Greeter greeter = Greeter.greeter(args);" + # expect "76 Greeter greeter = Greeter.greeter(args);" exec_string = execute("list") - checker = Checker(r"list bp 1", "70%sGreeter greeter = Greeter\.greeter\(args\);"%spaces_pattern) + checker = Checker(r"list bp 1", "76%sGreeter greeter = Greeter\.greeter\(args\);"%spaces_pattern) checker.check(exec_string, skip_fails=False) # run a backtrace - # expect "#0 hello.Hello.main(java.lang.String[] *).* at hello.Hello.java:70" + # expect "#0 hello.Hello.main(java.lang.String[] *).* at hello.Hello.java:76" # expect "#1 0x[0-9a-f]+ in com.oracle.svm.core.code.IsolateEnterStub.JavaMainWrapper_run_.* at [a-z/]+/JavaMainWrapper.java:[0-9]+" exec_string = execute("backtrace") checker = Checker("backtrace hello.Hello::main", - [r"#0%shello\.Hello::main\(java\.lang\.String\[\] \*\)%s at hello/Hello\.java:70"%(spaces_pattern, wildcard_pattern), + [r"#0%shello\.Hello::main\(java\.lang\.String\[\] \*\)%s at hello/Hello\.java:76"%(spaces_pattern, wildcard_pattern), r"#1%s%s in com\.oracle\.svm\.core\.JavaMainWrapper::runCore%s at %sJavaMainWrapper\.java:[0-9]+"%(spaces_pattern, address_pattern, wildcard_pattern, package_pattern), r"#2%s com\.oracle\.svm\.core\.JavaMainWrapper::run%s at %sJavaMainWrapper\.java:[0-9]+"%(spaces_pattern, wildcard_pattern, package_pattern), r"#3%s%s in com\.oracle\.svm\.core\.code\.IsolateEnterStub::JavaMainWrapper_run_%s%s"%(spaces_pattern, address_pattern, hex_digits_pattern, wildcard_pattern) @@ -343,10 +354,17 @@ def test(): rexp = [r"type = class java\.lang\.Object : public _objhdr {", r"%spublic:"%(spaces_pattern), r"%svoid Object\(void\);"%(spaces_pattern), + r"%sprotected:"%(spaces_pattern), + r"%sjava\.lang\.Object \* clone\(void\);"%(spaces_pattern), + r"%spublic:"%(spaces_pattern), r"%sboolean equals\(java\.lang\.Object \*\);"%(spaces_pattern), - r"%sprivate:"%(spaces_pattern), r"%sint hashCode\(void\);"%(spaces_pattern), + r"%svoid notify\(void\);"%(spaces_pattern), + r"%svoid notifyAll\(void\);"%(spaces_pattern), r"%sjava\.lang\.String \* toString\(void\);"%(spaces_pattern), + r"%svoid wait\(void\);"%(spaces_pattern), + r"%svoid wait\(long\);"%(spaces_pattern), + r"%svoid wait\(long, int\);"%(spaces_pattern), r"}"] checker = Checker('ptype Object', rexp) @@ -386,7 +404,7 @@ def test(): exec_string = execute("backtrace") checker = Checker("backtrace hello.Hello.Greeter::greeter", [r"#0%shello\.Hello\$Greeter::greeter\(java\.lang\.String\[\] \*\)%s at hello/Hello\.java:37"%(spaces_pattern, wildcard_pattern), - r"#1%s%s in hello\.Hello::main\(java\.lang\.String\[\] \*\)%s at hello/Hello\.java:70"%(spaces_pattern, address_pattern, wildcard_pattern), + r"#1%s%s in hello\.Hello::main\(java\.lang\.String\[\] \*\)%s at hello/Hello\.java:76"%(spaces_pattern, address_pattern, wildcard_pattern), r"#2%s%s in com\.oracle\.svm\.core\.JavaMainWrapper::runCore%s at %sJavaMainWrapper\.java:[0-9]+"%(spaces_pattern, address_pattern, wildcard_pattern, package_pattern), r"#3%scom\.oracle\.svm\.core\.JavaMainWrapper::run%s at %sJavaMainWrapper\.java:[0-9]+"%(spaces_pattern, wildcard_pattern, package_pattern), r"#4%s%s in com\.oracle\.svm\.core\.code\.IsolateEnterStub::JavaMainWrapper_run_%s%s"%(spaces_pattern, address_pattern, hex_digits_pattern, wildcard_pattern) @@ -430,11 +448,11 @@ def test(): # expect "#0 java.io.PrintStream::println(java.lang.String).* at java.base/java/io/PrintStream.java:[0-9]+" exec_string = execute("backtrace 6") rexp = [r"#0%sjava\.io\.PrintStream::println\(java\.lang\.String \*\)%s at %sjava/io/PrintStream.java:%s"%(spaces_pattern, wildcard_pattern, wildcard_pattern, digits_pattern), - r"#1%s%s in hello\.SubstituteHelperClass::nestedGreet\(void\) \(\) at hello/Target_hello_Hello_DefaultGreeter\.java:59"%(spaces_pattern, address_pattern), - r"#2%s%s in hello\.SubstituteHelperClass::staticInlineGreet \(\) at hello/Target_hello_Hello_DefaultGreeter\.java:53"%(spaces_pattern, address_pattern), - r"#3%s hello\.SubstituteHelperClass::inlineGreet \(\) at hello/Target_hello_Hello_DefaultGreeter\.java:48"%(spaces_pattern), - r"#4%s hello\.Hello\$DefaultGreeter::greet\(void\) \(\) at hello/Target_hello_Hello_DefaultGreeter\.java:40"%(spaces_pattern), - r"#5%s%s in hello\.Hello::main\(java\.lang\.String\[\] \*\) \(\) at hello/Hello\.java:71"%(spaces_pattern, address_pattern)] + r"#1%s%s in hello\.SubstituteHelperClass::nestedGreet\(void\) \(\) at hello/Target_hello_Hello_DefaultGreeter\.java:68"%(spaces_pattern, address_pattern), + r"#2%s%s in hello\.SubstituteHelperClass::staticInlineGreet \(\) at hello/Target_hello_Hello_DefaultGreeter\.java:62"%(spaces_pattern, address_pattern), + r"#3%s hello\.SubstituteHelperClass::inlineGreet \(\) at hello/Target_hello_Hello_DefaultGreeter\.java:57"%(spaces_pattern), + r"#4%s hello\.Hello\$DefaultGreeter::greet\(void\) \(\) at hello/Target_hello_Hello_DefaultGreeter\.java:49"%(spaces_pattern), + r"#5%s%s in hello\.Hello::main\(java\.lang\.String\[\] \*\) \(\) at hello/Hello\.java:77"%(spaces_pattern, address_pattern)] checker = Checker("backtrace PrintStream::println", rexp) checker.check(exec_string) @@ -535,7 +553,7 @@ def test(): # list inlineMee and inlineMoo and check that the listing maps to the inlined code instead of the actual code, # although not ideal this is how GDB treats inlined code in C/C++ as well - rexp = [r"109%sSystem\.out\.println\(\"This is a cow\"\);"%spaces_pattern] + rexp = [r"115%sSystem\.out\.println\(\"This is a cow\"\);"%spaces_pattern] checker = Checker('list inlineMee', rexp) checker.check(execute("list inlineMee")) checker = Checker('list inlineMoo', rexp) @@ -551,134 +569,134 @@ def test(): exec_string = execute("info break 4") # The breakpoint will be set to the inlined code instead of the actual code, # although not ideal this is how GDB treats inlined code in C/C++ as well - rexp = [r"4.1%sy%s%s in hello\.Hello::inlineMee at hello/Hello\.java:109"%(spaces_pattern, spaces_pattern, address_pattern), - r"4.2%sy%s%s in hello\.Hello::inlineMee at hello/Hello\.java:109"%(spaces_pattern, spaces_pattern, address_pattern), - r"4.3%sy%s%s in hello\.Hello::inlineMee at hello/Hello\.java:109"%(spaces_pattern, spaces_pattern, address_pattern)] + rexp = [r"4.1%sy%s%s in hello\.Hello::inlineMee at hello/Hello\.java:115"%(spaces_pattern, spaces_pattern, address_pattern), + r"4.2%sy%s%s in hello\.Hello::inlineMee at hello/Hello\.java:115"%(spaces_pattern, spaces_pattern, address_pattern), + r"4.3%sy%s%s in hello\.Hello::inlineMee at hello/Hello\.java:115"%(spaces_pattern, spaces_pattern, address_pattern)] checker = Checker('info break inlineMee', rexp) checker.check(exec_string) execute("continue") exec_string = execute("list") - rexp = [r"104%sinlineMoo\(\);"%spaces_pattern] + rexp = [r"110%sinlineMoo\(\);"%spaces_pattern] checker = Checker('hit break at inlineMee', rexp) checker.check(exec_string, skip_fails=False) execute("step") exec_string = execute("list") - rexp = [r"109%sSystem\.out\.println\(\"This is a cow\"\);"%spaces_pattern] + rexp = [r"115%sSystem\.out\.println\(\"This is a cow\"\);"%spaces_pattern] checker = Checker('step in inlineMee', rexp) checker.check(exec_string, skip_fails=False) exec_string = execute("backtrace 4") - rexp = [r"#0%shello\.Hello::inlineMoo \(\) at hello/Hello\.java:109"%spaces_pattern, - r"#1%shello\.Hello::inlineMee \(\) at hello/Hello\.java:104"%spaces_pattern, - r"#2%shello\.Hello::noInlineFoo\(void\) \(\) at hello/Hello\.java:94"%spaces_pattern, - r"#3%s%s in hello\.Hello::main\(java\.lang\.String\[\] \*\) \(\) at hello/Hello\.java:85"%(spaces_pattern, address_pattern)] + rexp = [r"#0%shello\.Hello::inlineMoo \(\) at hello/Hello\.java:115"%spaces_pattern, + r"#1%shello\.Hello::inlineMee \(\) at hello/Hello\.java:110"%spaces_pattern, + r"#2%shello\.Hello::noInlineFoo\(void\) \(\) at hello/Hello\.java:100"%spaces_pattern, + r"#3%s%s in hello\.Hello::main\(java\.lang\.String\[\] \*\) \(\) at hello/Hello\.java:91"%(spaces_pattern, address_pattern)] checker = Checker('backtrace inlineMee', rexp) checker.check(exec_string, skip_fails=False) execute("continue") exec_string = execute("list") - rexp = [r"104%sinlineMoo\(\);"%spaces_pattern] + rexp = [r"110%sinlineMoo\(\);"%spaces_pattern] checker = Checker('hit break at inlineMee', rexp) checker.check(exec_string, skip_fails=False) execute("step") exec_string = execute("list") - rexp = [r"109%sSystem\.out\.println\(\"This is a cow\"\);"%spaces_pattern] + rexp = [r"115%sSystem\.out\.println\(\"This is a cow\"\);"%spaces_pattern] checker = Checker('step in inlineMee', rexp) checker.check(exec_string, skip_fails=False) exec_string = execute("backtrace 4") - rexp = [r"#0%shello\.Hello::inlineMoo \(\) at hello/Hello\.java:109"%spaces_pattern, - r"#1%shello\.Hello::inlineMee \(\) at hello/Hello\.java:104"%spaces_pattern, - r"#2%shello\.Hello::inlineCallChain \(\) at hello/Hello\.java:99"%spaces_pattern, - r"#3%shello\.Hello::main\(java\.lang\.String\[\] \*\) \(\) at hello/Hello\.java:86"%spaces_pattern] + rexp = [r"#0%shello\.Hello::inlineMoo \(\) at hello/Hello\.java:115"%spaces_pattern, + r"#1%shello\.Hello::inlineMee \(\) at hello/Hello\.java:110"%spaces_pattern, + r"#2%shello\.Hello::inlineCallChain \(\) at hello/Hello\.java:105"%spaces_pattern, + r"#3%shello\.Hello::main\(java\.lang\.String\[\] \*\) \(\) at hello/Hello\.java:92"%spaces_pattern] checker = Checker('backtrace inlineMee 2', rexp) checker.check(exec_string, skip_fails=False) execute("delete breakpoints") exec_string = execute("break hello.Hello::noInlineTest") - rexp = r"Breakpoint %s at %s: file hello/Hello\.java, line 129\."%(digits_pattern, address_pattern) + rexp = r"Breakpoint %s at %s: file hello/Hello\.java, line 135\."%(digits_pattern, address_pattern) checker = Checker('break noInlineTest', rexp) checker.check(exec_string, skip_fails=False) execute("continue") exec_string = execute("list") - rexp = r"129%sSystem.out.println\(\"This is a test\"\);"%spaces_pattern + rexp = r"135%sSystem.out.println\(\"This is a test\"\);"%spaces_pattern checker = Checker('hit breakpoint in noInlineTest', rexp) checker.check(exec_string, skip_fails=False) exec_string = execute("backtrace 5") - rexp = [r"#0%shello\.Hello::noInlineTest\(void\) \(\) at hello/Hello\.java:129"%(spaces_pattern), - r"#1%s%s in hello\.Hello::inlineA \(\) at hello/Hello\.java:124"%(spaces_pattern, address_pattern), - r"#2%shello\.Hello::inlineIs \(\) at hello/Hello\.java:119"%(spaces_pattern), - r"#3%shello\.Hello::noInlineThis\(void\) \(\) at hello/Hello\.java:114"%(spaces_pattern), - r"#4%s%s in hello\.Hello::main\(java\.lang\.String\[\] \*\) \(\) at hello/Hello\.java:87"%(spaces_pattern, address_pattern)] + rexp = [r"#0%shello\.Hello::noInlineTest\(void\) \(\) at hello/Hello\.java:135"%(spaces_pattern), + r"#1%s%s in hello\.Hello::inlineA \(\) at hello/Hello\.java:130"%(spaces_pattern, address_pattern), + r"#2%shello\.Hello::inlineIs \(\) at hello/Hello\.java:125"%(spaces_pattern), + r"#3%shello\.Hello::noInlineThis\(void\) \(\) at hello/Hello\.java:120"%(spaces_pattern), + r"#4%s%s in hello\.Hello::main\(java\.lang\.String\[\] \*\) \(\) at hello/Hello\.java:93"%(spaces_pattern, address_pattern)] checker = Checker('backtrace in inlineMethod', rexp) checker.check(exec_string, skip_fails=False) execute("delete breakpoints") - exec_string = execute("break Hello.java:149") - rexp = r"Breakpoint %s at %s: file hello/Hello\.java, line 149\."%(digits_pattern, address_pattern) - checker = Checker('break Hello.java:149', rexp) + exec_string = execute("break Hello.java:155") + rexp = r"Breakpoint %s at %s: file hello/Hello\.java, line 155\."%(digits_pattern, address_pattern) + checker = Checker('break Hello.java:155', rexp) checker.check(exec_string) execute("continue 5") exec_string = execute("backtrace 14") - rexp = [r"#0%shello\.Hello::inlineMixTo \(\) at hello/Hello\.java:149"%(spaces_pattern), - r"#1%shello\.Hello::noInlineHere\(int\) \(\) at hello/Hello\.java:141"%(spaces_pattern), - r"#2%s%s in hello\.Hello::inlineMixTo \(\) at hello/Hello\.java:147"%(spaces_pattern, address_pattern), - r"#3%shello\.Hello::noInlineHere\(int\) \(\) at hello/Hello\.java:141"%(spaces_pattern), - r"#4%s%s in hello\.Hello::inlineMixTo \(\) at hello/Hello\.java:147"%(spaces_pattern, address_pattern), - r"#5%shello\.Hello::noInlineHere\(int\) \(\) at hello/Hello\.java:141"%(spaces_pattern), - r"#6%s%s in hello\.Hello::inlineMixTo \(\) at hello/Hello\.java:147"%(spaces_pattern, address_pattern), - r"#7%shello\.Hello::noInlineHere\(int\) \(\) at hello/Hello\.java:141"%(spaces_pattern), - r"#8%s%s in hello\.Hello::inlineMixTo \(\) at hello/Hello\.java:147"%(spaces_pattern, address_pattern), - r"#9%shello\.Hello::noInlineHere\(int\) \(\) at hello/Hello\.java:141"%(spaces_pattern), - r"#10%s%s in hello\.Hello::inlineMixTo \(\) at hello/Hello\.java:147"%(spaces_pattern, address_pattern), - r"#11%shello\.Hello::noInlineHere\(int\) \(\) at hello/Hello\.java:141"%(spaces_pattern), - r"#12%s%s in hello\.Hello::inlineFrom \(\) at hello/Hello\.java:134"%(spaces_pattern, address_pattern), - r"#13%shello\.Hello::main\(java\.lang\.String\[\] \*\) \(\) at hello/Hello\.java:88"%(spaces_pattern)] + rexp = [r"#0%shello\.Hello::inlineMixTo \(\) at hello/Hello\.java:155"%(spaces_pattern), + r"#1%shello\.Hello::noInlineHere\(int\) \(\) at hello/Hello\.java:147"%(spaces_pattern), + r"#2%s%s in hello\.Hello::inlineMixTo \(\) at hello/Hello\.java:153"%(spaces_pattern, address_pattern), + r"#3%shello\.Hello::noInlineHere\(int\) \(\) at hello/Hello\.java:147"%(spaces_pattern), + r"#4%s%s in hello\.Hello::inlineMixTo \(\) at hello/Hello\.java:153"%(spaces_pattern, address_pattern), + r"#5%shello\.Hello::noInlineHere\(int\) \(\) at hello/Hello\.java:147"%(spaces_pattern), + r"#6%s%s in hello\.Hello::inlineMixTo \(\) at hello/Hello\.java:153"%(spaces_pattern, address_pattern), + r"#7%shello\.Hello::noInlineHere\(int\) \(\) at hello/Hello\.java:147"%(spaces_pattern), + r"#8%s%s in hello\.Hello::inlineMixTo \(\) at hello/Hello\.java:153"%(spaces_pattern, address_pattern), + r"#9%shello\.Hello::noInlineHere\(int\) \(\) at hello/Hello\.java:147"%(spaces_pattern), + r"#10%s%s in hello\.Hello::inlineMixTo \(\) at hello/Hello\.java:153"%(spaces_pattern, address_pattern), + r"#11%shello\.Hello::noInlineHere\(int\) \(\) at hello/Hello\.java:147"%(spaces_pattern), + r"#12%s%s in hello\.Hello::inlineFrom \(\) at hello/Hello\.java:140"%(spaces_pattern, address_pattern), + r"#13%shello\.Hello::main\(java\.lang\.String\[\] \*\) \(\) at hello/Hello\.java:94"%(spaces_pattern)] checker = Checker('backtrace in recursive inlineMixTo', rexp) checker.check(exec_string, skip_fails=False) execute("delete breakpoints") - exec_string = execute("break Hello.java:162") - rexp = r"Breakpoint %s at %s: Hello\.java:162\. \(2 locations\)"%(digits_pattern, address_pattern) - checker = Checker('break Hello.java:162', rexp) + exec_string = execute("break Hello.java:168") + rexp = r"Breakpoint %s at %s: Hello\.java:168\. \(2 locations\)"%(digits_pattern, address_pattern) + checker = Checker('break Hello.java:168', rexp) checker.check(exec_string) execute("continue 5") exec_string = execute("backtrace 14") - rexp = [r"#0%shello\.Hello::inlineTo\(int\) \(\) at hello/Hello\.java:162"%(spaces_pattern), - r"#1%s%s in hello\.Hello::inlineHere \(\) at hello/Hello\.java:154"%(spaces_pattern, address_pattern), - r"#2%shello\.Hello::inlineTo\(int\) \(\) at hello/Hello\.java:160"%(spaces_pattern), - r"#3%s%s in hello\.Hello::inlineHere \(\) at hello/Hello\.java:154"%(spaces_pattern, address_pattern), - r"#4%shello\.Hello::inlineTo\(int\) \(\) at hello/Hello\.java:160"%(spaces_pattern), - r"#5%s%s in hello\.Hello::inlineHere \(\) at hello/Hello\.java:154"%(spaces_pattern, address_pattern), - r"#6%shello\.Hello::inlineTo\(int\) \(\) at hello/Hello\.java:160"%(spaces_pattern), - r"#7%s%s in hello\.Hello::inlineHere \(\) at hello/Hello\.java:154"%(spaces_pattern, address_pattern), - r"#8%shello\.Hello::inlineTo\(int\) \(\) at hello/Hello\.java:160"%(spaces_pattern), - r"#9%s%s in hello\.Hello::inlineHere \(\) at hello/Hello\.java:154"%(spaces_pattern, address_pattern), - r"#10%shello\.Hello::inlineTo \(\) at hello/Hello\.java:160"%(spaces_pattern), - r"#11%shello\.Hello::inlineHere \(\) at hello/Hello\.java:154"%(spaces_pattern), - r"#12%shello\.Hello::inlineFrom \(\) at hello/Hello\.java:135"%(spaces_pattern), - r"#13%shello\.Hello::main\(java\.lang\.String\[\] \*\) \(\) at hello/Hello\.java:88"%(spaces_pattern)] + rexp = [r"#0%shello\.Hello::inlineTo\(int\) \(\) at hello/Hello\.java:168"%(spaces_pattern), + r"#1%s%s in hello\.Hello::inlineHere \(\) at hello/Hello\.java:160"%(spaces_pattern, address_pattern), + r"#2%shello\.Hello::inlineTo\(int\) \(\) at hello/Hello\.java:166"%(spaces_pattern), + r"#3%s%s in hello\.Hello::inlineHere \(\) at hello/Hello\.java:160"%(spaces_pattern, address_pattern), + r"#4%shello\.Hello::inlineTo\(int\) \(\) at hello/Hello\.java:166"%(spaces_pattern), + r"#5%s%s in hello\.Hello::inlineHere \(\) at hello/Hello\.java:160"%(spaces_pattern, address_pattern), + r"#6%shello\.Hello::inlineTo\(int\) \(\) at hello/Hello\.java:166"%(spaces_pattern), + r"#7%s%s in hello\.Hello::inlineHere \(\) at hello/Hello\.java:160"%(spaces_pattern, address_pattern), + r"#8%shello\.Hello::inlineTo\(int\) \(\) at hello/Hello\.java:166"%(spaces_pattern), + r"#9%s%s in hello\.Hello::inlineHere \(\) at hello/Hello\.java:160"%(spaces_pattern, address_pattern), + r"#10%shello\.Hello::inlineTo \(\) at hello/Hello\.java:166"%(spaces_pattern), + r"#11%shello\.Hello::inlineHere \(\) at hello/Hello\.java:160"%(spaces_pattern), + r"#12%shello\.Hello::inlineFrom \(\) at hello/Hello\.java:141"%(spaces_pattern), + r"#13%shello\.Hello::main\(java\.lang\.String\[\] \*\) \(\) at hello/Hello\.java:94"%(spaces_pattern)] checker = Checker('backtrace in recursive inlineTo', rexp) checker.check(exec_string, skip_fails=False) execute("delete breakpoints") - exec_string = execute("break Hello.java:168") - rexp = r"Breakpoint %s at %s: file hello/Hello\.java, line 168\."%(digits_pattern, address_pattern) - checker = Checker('break Hello.java:168', rexp) + exec_string = execute("break Hello.java:174") + rexp = r"Breakpoint %s at %s: file hello/Hello\.java, line 174\."%(digits_pattern, address_pattern) + checker = Checker('break Hello.java:174', rexp) checker.check(exec_string) execute("continue 5") exec_string = execute("backtrace 8") - rexp = [r"#0%shello\.Hello::inlineTailRecursion\(int\) \(\) at hello/Hello\.java:168"%(spaces_pattern), - r"#1%s%s in hello\.Hello::inlineTailRecursion\(int\) \(\) at hello/Hello\.java:171"%(spaces_pattern, address_pattern), - r"#2%s%s in hello\.Hello::inlineTailRecursion\(int\) \(\) at hello/Hello\.java:171"%(spaces_pattern, address_pattern), - r"#3%s%s in hello\.Hello::inlineTailRecursion\(int\) \(\) at hello/Hello\.java:171"%(spaces_pattern, address_pattern), - r"#4%s%s in hello\.Hello::inlineTailRecursion\(int\) \(\) at hello/Hello\.java:171"%(spaces_pattern, address_pattern), - r"#5%s%s in hello\.Hello::inlineTailRecursion \(\) at hello/Hello\.java:171"%(spaces_pattern, address_pattern), - r"#6%shello\.Hello::inlineFrom \(\) at hello/Hello\.java:136"%(spaces_pattern), - r"#7%shello\.Hello::main\(java\.lang\.String\[\] \*\) \(\) at hello/Hello\.java:88"%(spaces_pattern)] + rexp = [r"#0%shello\.Hello::inlineTailRecursion\(int\) \(\) at hello/Hello\.java:174"%(spaces_pattern), + r"#1%s%s in hello\.Hello::inlineTailRecursion\(int\) \(\) at hello/Hello\.java:177"%(spaces_pattern, address_pattern), + r"#2%s%s in hello\.Hello::inlineTailRecursion\(int\) \(\) at hello/Hello\.java:177"%(spaces_pattern, address_pattern), + r"#3%s%s in hello\.Hello::inlineTailRecursion\(int\) \(\) at hello/Hello\.java:177"%(spaces_pattern, address_pattern), + r"#4%s%s in hello\.Hello::inlineTailRecursion\(int\) \(\) at hello/Hello\.java:177"%(spaces_pattern, address_pattern), + r"#5%s%s in hello\.Hello::inlineTailRecursion \(\) at hello/Hello\.java:177"%(spaces_pattern, address_pattern), + r"#6%shello\.Hello::inlineFrom \(\) at hello/Hello\.java:142"%(spaces_pattern), + r"#7%shello\.Hello::main\(java\.lang\.String\[\] \*\) \(\) at hello/Hello\.java:94"%(spaces_pattern)] checker = Checker('backtrace in recursive inlineTo', rexp) checker.check(exec_string, skip_fails=False) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AnalysisObjectScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AnalysisObjectScanner.java index f7ab722b8ca1..2f1d0f066323 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AnalysisObjectScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AnalysisObjectScanner.java @@ -24,111 +24,11 @@ */ package com.oracle.graal.pointsto; -import com.oracle.graal.pointsto.flow.ArrayElementsTypeFlow; -import com.oracle.graal.pointsto.flow.FieldTypeFlow; -import com.oracle.graal.pointsto.flow.context.object.AnalysisObject; -import com.oracle.graal.pointsto.meta.AnalysisField; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.typestate.TypeState; import com.oracle.graal.pointsto.util.CompletionExecutor; -import jdk.vm.ci.meta.JavaConstant; - public class AnalysisObjectScanner extends ObjectScanner { public AnalysisObjectScanner(BigBang bb, CompletionExecutor executor, ReusableSet scannedObjects) { - super(bb, executor, scannedObjects); - } - - @Override - public void forRelocatedPointerFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue) { - if (!field.isWritten()) { - field.registerAsWritten(null); - } - } - - @Override - public void forNullFieldValue(JavaConstant receiver, AnalysisField field) { - FieldTypeFlow fieldTypeFlow = getFieldTypeFlow(field, receiver); - if (!fieldTypeFlow.getState().canBeNull()) { - /* Signal that the field can contain null. */ - fieldTypeFlow.addState(getAnalysis(), TypeState.forNull()); - } - } - - @Override - public void forNonNullFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue) { - PointsToAnalysis analysis = getAnalysis(); - AnalysisType fieldType = analysis.getMetaAccess().lookupJavaType(analysis.getSnippetReflectionProvider().asObject(Object.class, fieldValue).getClass()); - assert fieldType.isInstantiated() : fieldType; - - /* Add the constant value object to the field's type flow. */ - FieldTypeFlow fieldTypeFlow = getFieldTypeFlow(field, receiver); - AnalysisObject constantObject = bb.analysisPolicy().createConstantObject(analysis, fieldValue, fieldType); - if (!fieldTypeFlow.getState().containsObject(constantObject)) { - /* Add the new constant to the field's flow state. */ - TypeState constantTypeState = TypeState.forNonNullObject(analysis, constantObject); - fieldTypeFlow.addState(analysis, constantTypeState); - } - } - - /** Get the field type flow give a receiver. */ - private FieldTypeFlow getFieldTypeFlow(AnalysisField field, JavaConstant receiver) { - /* The field type flow is used to track the constant field value. */ - if (field.isStatic()) { - /* If the field is static it comes from the originalRoots. */ - return field.getStaticFieldFlow(); - } else { - /* - * The field comes from a constant scan, thus it's type flow is mapped to the unique - * constant object. - */ - PointsToAnalysis analysis = getAnalysis(); - AnalysisType receiverType = analysis.getMetaAccess().lookupJavaType(analysis.getSnippetReflectionProvider().asObject(Object.class, receiver).getClass()); - AnalysisObject constantReceiverObj = analysis.analysisPolicy().createConstantObject(analysis, receiver, receiverType); - return constantReceiverObj.getInstanceFieldFlow(analysis, field, true); - } - } - - @Override - public void forNullArrayElement(JavaConstant array, AnalysisType arrayType, int elementIndex) { - ArrayElementsTypeFlow arrayObjElementsFlow = getArrayElementsFlow(array, arrayType); - if (!arrayObjElementsFlow.getState().canBeNull()) { - /* Signal that the constant array can contain null. */ - arrayObjElementsFlow.addState(getAnalysis(), TypeState.forNull()); - } - } - - @Override - public void forNonNullArrayElement(JavaConstant array, AnalysisType arrayType, JavaConstant elementConstant, AnalysisType elementType, int elementIndex) { - assert elementType.isInstantiated() : elementType; - ArrayElementsTypeFlow arrayObjElementsFlow = getArrayElementsFlow(array, arrayType); - PointsToAnalysis analysis = getAnalysis(); - AnalysisObject constantObject = bb.analysisPolicy().createConstantObject(analysis, elementConstant, elementType); - if (!arrayObjElementsFlow.getState().containsObject(constantObject)) { - /* Add the constant element to the constant's array type flow. */ - TypeState elementTypeState = TypeState.forNonNullObject(analysis, constantObject); - arrayObjElementsFlow.addState(analysis, elementTypeState); - } - } - - /** Get the array elements flow given its type and the array constant. */ - private ArrayElementsTypeFlow getArrayElementsFlow(JavaConstant array, AnalysisType arrayType) { - PointsToAnalysis analysis = getAnalysis(); - AnalysisObject arrayObjConstant = analysis.analysisPolicy().createConstantObject(analysis, array, arrayType); - return arrayObjConstant.getArrayElementsFlow(analysis, true); - } - - @Override - protected void forScannedConstant(JavaConstant value, ScanReason reason) { - PointsToAnalysis analysis = getAnalysis(); - Object valueObj = analysis.getSnippetReflectionProvider().asObject(Object.class, value); - AnalysisType type = bb.getMetaAccess().lookupJavaType(valueObj.getClass()); - - type.registerAsInHeap(); - } - - private PointsToAnalysis getAnalysis() { - return ((PointsToAnalysis) bb); + super(bb, executor, scannedObjects, new AnalysisObjectScanningObserver(bb)); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AnalysisObjectScanningObserver.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AnalysisObjectScanningObserver.java new file mode 100644 index 000000000000..3dca19404a31 --- /dev/null +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AnalysisObjectScanningObserver.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.pointsto; + +import com.oracle.graal.pointsto.flow.ArrayElementsTypeFlow; +import com.oracle.graal.pointsto.flow.FieldTypeFlow; +import com.oracle.graal.pointsto.flow.context.object.AnalysisObject; +import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.typestate.TypeState; + +import jdk.vm.ci.meta.JavaConstant; + +public class AnalysisObjectScanningObserver implements ObjectScanningObserver { + + private final BigBang bb; + + public AnalysisObjectScanningObserver(BigBang bb) { + this.bb = bb; + } + + @Override + public void forRelocatedPointerFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue) { + if (!field.isWritten()) { + field.registerAsWritten(null); + } + } + + @Override + public void forNullFieldValue(JavaConstant receiver, AnalysisField field) { + FieldTypeFlow fieldTypeFlow = getFieldTypeFlow(field, receiver); + if (!fieldTypeFlow.getState().canBeNull()) { + /* Signal that the field can contain null. */ + fieldTypeFlow.addState(getAnalysis(), TypeState.forNull()); + } + } + + @Override + public void forNonNullFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue) { + PointsToAnalysis analysis = getAnalysis(); + AnalysisType fieldType = analysis.getMetaAccess().lookupJavaType(analysis.getSnippetReflectionProvider().asObject(Object.class, fieldValue).getClass()); + assert fieldType.isInstantiated() : fieldType; + + /* Add the constant value object to the field's type flow. */ + FieldTypeFlow fieldTypeFlow = getFieldTypeFlow(field, receiver); + AnalysisObject constantObject = bb.analysisPolicy().createConstantObject(analysis, fieldValue, fieldType); + if (!fieldTypeFlow.getState().containsObject(constantObject)) { + /* Add the new constant to the field's flow state. */ + TypeState constantTypeState = TypeState.forNonNullObject(analysis, constantObject); + fieldTypeFlow.addState(analysis, constantTypeState); + } + } + + /** + * Get the field type flow give a receiver. + */ + private FieldTypeFlow getFieldTypeFlow(AnalysisField field, JavaConstant receiver) { + /* The field type flow is used to track the constant field value. */ + if (field.isStatic()) { + /* If the field is static it comes from the originalRoots. */ + return field.getStaticFieldFlow(); + } else { + /* + * The field comes from a constant scan, thus it's type flow is mapped to the unique + * constant object. + */ + PointsToAnalysis analysis = getAnalysis(); + AnalysisType receiverType = analysis.getMetaAccess().lookupJavaType(analysis.getSnippetReflectionProvider().asObject(Object.class, receiver).getClass()); + AnalysisObject constantReceiverObj = analysis.analysisPolicy().createConstantObject(analysis, receiver, receiverType); + return constantReceiverObj.getInstanceFieldFlow(analysis, field, true); + } + } + + @Override + public void forNullArrayElement(JavaConstant array, AnalysisType arrayType, int elementIndex) { + ArrayElementsTypeFlow arrayObjElementsFlow = getArrayElementsFlow(array, arrayType); + if (!arrayObjElementsFlow.getState().canBeNull()) { + /* Signal that the constant array can contain null. */ + arrayObjElementsFlow.addState(getAnalysis(), TypeState.forNull()); + } + } + + @Override + public void forNonNullArrayElement(JavaConstant array, AnalysisType arrayType, JavaConstant elementConstant, AnalysisType elementType, int elementIndex) { + assert elementType.isInstantiated() : elementType; + ArrayElementsTypeFlow arrayObjElementsFlow = getArrayElementsFlow(array, arrayType); + PointsToAnalysis analysis = getAnalysis(); + AnalysisObject constantObject = bb.analysisPolicy().createConstantObject(analysis, elementConstant, elementType); + if (!arrayObjElementsFlow.getState().containsObject(constantObject)) { + /* Add the constant element to the constant's array type flow. */ + TypeState elementTypeState = TypeState.forNonNullObject(analysis, constantObject); + arrayObjElementsFlow.addState(analysis, elementTypeState); + } + } + + /** + * Get the array elements flow given its type and the array constant. + */ + private ArrayElementsTypeFlow getArrayElementsFlow(JavaConstant array, AnalysisType arrayType) { + PointsToAnalysis analysis = getAnalysis(); + AnalysisObject arrayObjConstant = analysis.analysisPolicy().createConstantObject(analysis, array, arrayType); + return arrayObjConstant.getArrayElementsFlow(analysis, true); + } + + @Override + public void forScannedConstant(JavaConstant value, ObjectScanner.ScanReason reason) { + PointsToAnalysis analysis = getAnalysis(); + Object valueObj = analysis.getSnippetReflectionProvider().asObject(Object.class, value); + AnalysisType type = bb.getMetaAccess().lookupJavaType(valueObj.getClass()); + + type.registerAsInHeap(); + } + + private PointsToAnalysis getAnalysis() { + return ((PointsToAnalysis) bb); + } +} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java index 4d34825d0c7e..b17b5d7707ea 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java @@ -26,6 +26,7 @@ import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; +import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.graal.pointsto.util.Timer; import jdk.vm.ci.meta.ConstantReflectionProvider; @@ -36,6 +37,7 @@ import java.io.PrintWriter; import java.util.List; +import java.util.function.Function; /** * Central static analysis interface that groups together the functionality of reachability analysis @@ -92,4 +94,6 @@ public interface BigBang extends ReachabilityAnalysis, HeapScanning { Runnable getHeartbeatCallback(); boolean extendedAsserts(); + + void runAnalysis(DebugContext debug, Function duringAnalysisAction) throws InterruptedException; } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/DefaultAnalysisPolicy.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/DefaultAnalysisPolicy.java index 7b791018a845..7104dbb620e7 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/DefaultAnalysisPolicy.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/DefaultAnalysisPolicy.java @@ -189,7 +189,7 @@ public void onObservedUpdate(PointsToAnalysis bb) { receiverState = filterReceiverState(bb, receiverState); } - for (AnalysisType type : receiverState.types()) { + for (AnalysisType type : receiverState.types(bb)) { if (isSaturated()) { /*- * The receiver can become saturated during the callees linking, which saturates diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java index b633afcb2b81..95afbaa4f2b4 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java @@ -30,10 +30,14 @@ import java.util.Comparator; import java.util.Deque; import java.util.IdentityHashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.atomic.AtomicInteger; +import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.debug.DebugHandlersFactory; +import org.graalvm.compiler.options.OptionValues; import org.graalvm.word.WordBase; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; @@ -42,6 +46,7 @@ import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.graal.pointsto.util.CompletionExecutor; +import com.oracle.graal.pointsto.util.CompletionExecutor.DebugContextRunnable; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.meta.JavaConstant; @@ -60,9 +65,11 @@ public abstract class ObjectScanner { private final ReusableSet scannedObjects; private final CompletionExecutor executor; private final Deque worklist; + private final ObjectScanningObserver scanningObserver; - public ObjectScanner(BigBang bb, CompletionExecutor executor, ReusableSet scannedObjects) { + public ObjectScanner(BigBang bb, CompletionExecutor executor, ReusableSet scannedObjects, ObjectScanningObserver scanningObserver) { this.bb = bb; + this.scanningObserver = scanningObserver; if (executor != null) { this.executor = executor; this.worklist = null; @@ -102,12 +109,19 @@ public void scanBootImageHeapRoots(Comparator fieldComparator, Co private void execute(Runnable runnable) { if (executor != null) { - executor.execute(debug -> runnable.run()); + executor.execute((ObjectScannerRunnable) debug -> runnable.run()); } else { runnable.run(); } } + private interface ObjectScannerRunnable extends DebugContextRunnable { + @Override + default DebugContext getDebug(OptionValues options, List factories) { + return DebugContext.disabled(null); + } + } + private void scanEmbeddedRoot(JavaConstant root, BytecodePosition position) { AnalysisMethod method = (AnalysisMethod) position.getMethod(); try { @@ -117,27 +131,6 @@ private void scanEmbeddedRoot(JavaConstant root, BytecodePosition position) { } } - /* - * When scanning a field there are three possible cases: the field value is a relocated pointer, - * the field value is null or the field value is non-null. The method {@link - * ObjectScanner#scanField(AnalysisField, JavaConstant, Object)} will call the appropriated - * method during scanning. - */ - - /** - * Hook for relocated pointer scanned field value. - * - * For relocated pointers the value is only known at runtime after methods are relocated, which - * is pretty much the same as a field written at runtime: we do not have a constant value. - */ - public abstract void forRelocatedPointerFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue); - - /** Hook for scanned null field value. */ - public abstract void forNullFieldValue(JavaConstant receiver, AnalysisField field); - - /** Hook for scanned non-null field value. */ - public abstract void forNonNullFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue); - /** * Scans the value of a root field. * @@ -168,14 +161,14 @@ protected final void scanField(AnalysisField field, JavaConstant receiver, Workl } if (fieldValue.getJavaKind() == JavaKind.Object && bb.getHostVM().isRelocatedPointer(constantAsObject(bb, fieldValue))) { - forRelocatedPointerFieldValue(receiver, field, fieldValue); + scanningObserver.forRelocatedPointerFieldValue(receiver, field, fieldValue); } else if (fieldValue.isNull()) { - forNullFieldValue(receiver, field); + scanningObserver.forNullFieldValue(receiver, field); } else if (fieldValue.getJavaKind() == JavaKind.Object) { /* Scan the field value. */ scanConstant(fieldValue, reason, previous); /* Process the field value. */ - forNonNullFieldValue(receiver, field, fieldValue); + scanningObserver.forNonNullFieldValue(receiver, field, fieldValue); } } catch (UnsupportedFeatureException ex) { @@ -183,18 +176,6 @@ protected final void scanField(AnalysisField field, JavaConstant receiver, Workl } } - /* - * When scanning array elements there are two possible cases: the element value is either null - * or the field value is non-null. The method {@link ObjectScanner#scanArray(JavaConstant, - * Object)} will call the appropriated method during scanning. - */ - - /** Hook for scanned null element value. */ - public abstract void forNullArrayElement(JavaConstant array, AnalysisType arrayType, int elementIndex); - - /** Hook for scanned non-null element value. */ - public abstract void forNonNullArrayElement(JavaConstant array, AnalysisType arrayType, JavaConstant elementConstant, AnalysisType elementType, int elementIndex); - /** * Scans constant arrays, one element at the time. * @@ -213,7 +194,7 @@ protected final void scanArray(JavaConstant array, WorklistEntry previous) { Object e = arrayObject[idx]; try { if (e == null) { - forNullArrayElement(array, arrayType, idx); + scanningObserver.forNullArrayElement(array, arrayType, idx); } else { Object element = bb.getUniverse().replaceObject(e); JavaConstant elementConstant = bb.getSnippetReflectionProvider().forObject(element); @@ -222,7 +203,7 @@ protected final void scanArray(JavaConstant array, WorklistEntry previous) { /* Scan the array element. */ scanConstant(elementConstant, reason, previous); /* Process the array element. */ - forNonNullArrayElement(array, arrayType, elementConstant, elementType, idx); + scanningObserver.forNonNullArrayElement(array, arrayType, elementConstant, elementType, idx); } } catch (UnsupportedFeatureException ex) { unsupportedFeature(arrayType.toJavaName(true), ex.getMessage(), reason, previous); @@ -230,12 +211,6 @@ protected final void scanArray(JavaConstant array, WorklistEntry previous) { } } - /** - * Hook for scanned constant. The subclasses can provide additional processing for the scanned - * constants. - */ - protected abstract void forScannedConstant(JavaConstant scannedValue, ScanReason reason); - public final void scanConstant(JavaConstant value, ScanReason reason) { scanConstant(value, reason, null); } @@ -251,12 +226,12 @@ public final void scanConstant(JavaConstant value, ScanReason reason, WorklistEn } if (scannedObjects.putAndAcquire(valueObj) == null) { try { - forScannedConstant(value, reason); + scanningObserver.forScannedConstant(value, reason); } finally { scannedObjects.release(valueObj); WorklistEntry worklistEntry = new WorklistEntry(previous, value, reason); if (executor != null) { - executor.execute(debug -> doScan(worklistEntry)); + executor.execute((ObjectScannerRunnable) debug -> doScan(worklistEntry)); } else { worklist.push(worklistEntry); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanningObserver.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanningObserver.java new file mode 100644 index 000000000000..9101fa4ab148 --- /dev/null +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanningObserver.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.pointsto; + +import com.oracle.graal.pointsto.ObjectScanner.ScanReason; +import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisType; + +import jdk.vm.ci.meta.JavaConstant; + +/** + * This interface contains hooks for constant scanning events. + * + * When scanning a field there are three possible cases: the field value is a relocated pointer, the + * field value is null or the field value is non-null. When scanning array elements there are two + * possible cases: the element value is either null or the field value is non-null. The implementers + * of this API will call the appropriate method during scanning. + */ +public interface ObjectScanningObserver { + + /** + * Hook for relocated pointer scanned field value. + *

    + * For relocated pointers the value is only known at runtime after methods are relocated, which + * is pretty much the same as a field written at runtime: we do not have a constant value. + */ + void forRelocatedPointerFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue); + + /** + * Hook for scanned null field value. + */ + void forNullFieldValue(JavaConstant receiver, AnalysisField field); + + /** + * Hook for scanned non-null field value. + */ + void forNonNullFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue); + + /** + * Hook for scanned null element value. + */ + void forNullArrayElement(JavaConstant array, AnalysisType arrayType, int elementIndex); + + /** + * Hook for scanned non-null element value. + */ + void forNonNullArrayElement(JavaConstant array, AnalysisType arrayType, JavaConstant elementConstant, AnalysisType elementType, int elementIndex); + + /** + * Hook for scanned constant. + */ + void forScannedConstant(JavaConstant scannedValue, ScanReason reason); +} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java index b7eca5883197..d0ffe5d796cf 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java @@ -43,9 +43,8 @@ import java.util.concurrent.ForkJoinWorkerThread; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLongArray; +import java.util.function.Function; -import com.oracle.graal.pointsto.flow.FieldTypeFlow; -import com.oracle.graal.pointsto.reports.StatisticsPrinter; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.core.common.SuppressFBWarnings; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; @@ -57,12 +56,14 @@ import org.graalvm.compiler.nodes.spi.Replacements; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.printer.GraalDebugHandlersFactory; +import org.graalvm.nativeimage.hosted.Feature; import com.oracle.graal.pointsto.ObjectScanner.ReusableSet; import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; import com.oracle.graal.pointsto.flow.AllSynchronizedTypeFlow; +import com.oracle.graal.pointsto.flow.FieldTypeFlow; import com.oracle.graal.pointsto.flow.MethodTypeFlow; import com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder; import com.oracle.graal.pointsto.flow.OffsetLoadTypeFlow.AbstractUnsafeLoadTypeFlow; @@ -76,8 +77,10 @@ import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.meta.HostedProviders; +import com.oracle.graal.pointsto.reports.StatisticsPrinter; import com.oracle.graal.pointsto.typestate.PointsToStats; import com.oracle.graal.pointsto.typestate.TypeState; +import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.graal.pointsto.util.CompletionExecutor; import com.oracle.graal.pointsto.util.CompletionExecutor.DebugContextRunnable; import com.oracle.graal.pointsto.util.Timer; @@ -435,6 +438,7 @@ public AnalysisMethod addRootMethod(Executable method) { @Override @SuppressWarnings("try") public AnalysisMethod addRootMethod(AnalysisMethod aMethod) { + assert !universe.sealed() : "Cannot register root methods after analysis universe is sealed."; if (aMethod.isRootMethod()) { return aMethod; } @@ -703,6 +707,64 @@ public HostVM getHostVM() { return hostVM; } + /** + * Iterate until analysis reaches a fixpoint. + * + * @param debugContext debug context + * @param analysisEndCondition hook for actions to be taken during analysis. It also dictates + * when the analysis should end, i.e., it returns true if no more iterations are + * required. + * + * When the analysis is used for Native Image generation the actions could for + * example be specified via + * {@link org.graalvm.nativeimage.hosted.Feature#duringAnalysis(Feature.DuringAnalysisAccess)}. + * The ending condition could be provided by + * {@link org.graalvm.nativeimage.hosted.Feature.DuringAnalysisAccess#requireAnalysisIteration()}. + * + * @throws AnalysisError if the analysis fails + */ + @SuppressWarnings("try") + @Override + public void runAnalysis(DebugContext debugContext, Function analysisEndCondition) throws InterruptedException { + int numIterations = 0; + while (true) { + try (Indent indent2 = debugContext.logAndIndent("new analysis iteration")) { + /* + * Do the analysis (which itself is done in a similar iterative process) + */ + boolean analysisChanged = finish(); + + numIterations++; + if (numIterations > 1000) { + /* + * Usually there are < 10 iterations. If we have so many iterations, we probably + * have an endless loop (but at least we have a performance problem because we + * re-start the analysis so often). + */ + throw AnalysisError.shouldNotReachHere(String.format("Static analysis did not reach a fix point after %d iterations because a Feature keeps requesting new analysis iterations. " + + "The analysis itself %s find a change in type states in the last iteration.", + numIterations, analysisChanged ? "DID" : "DID NOT")); + } + + /* + * Allow features to change the universe. + */ + try (StopTimer t2 = getProcessFeaturesTimer().start()) { + int numTypes = universe.getTypes().size(); + int numMethods = universe.getMethods().size(); + int numFields = universe.getFields().size(); + if (analysisEndCondition.apply(universe)) { + if (numTypes != universe.getTypes().size() || numMethods != universe.getMethods().size() || numFields != universe.getFields().size()) { + throw AnalysisError.shouldNotReachHere( + "When a feature makes more types, methods, or fields reachable, it must require another analysis iteration via DuringAnalysisAccess.requireAnalysisIteration()"); + } + return; + } + } + } + } + } + @SuppressFBWarnings(value = "NP_NONNULL_PARAM_VIOLATION", justification = "ForkJoinPool does support null for the exception handler.") public static ForkJoinPool createExecutor(DebugContext debug, int numberOfThreads) { ForkJoinPool.ForkJoinWorkerThreadFactory factory = debugThreadFactory(debug.areScopesEnabled() || debug.areMetricsEnabled() ? debug : null); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java index 018926e0f324..4b9e8f035a51 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java @@ -26,9 +26,7 @@ import java.lang.reflect.AnnotatedElement; import java.util.Optional; -import java.util.concurrent.ForkJoinPool; -import com.oracle.graal.pointsto.BigBang; import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; import org.graalvm.compiler.java.GraphBuilderPhase; @@ -38,6 +36,7 @@ import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.OptimisticOptimizations; +import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -55,8 +54,6 @@ public interface HostVM { OptionValues options(); - ForkJoinPool executor(); - boolean isRelocatedPointer(Object originalObject); void clearInThread(); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayCopyTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayCopyTypeFlow.java index e9f63856c75c..ed5eef62397c 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayCopyTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayCopyTypeFlow.java @@ -25,7 +25,6 @@ package com.oracle.graal.pointsto.flow; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.replacements.arraycopy.ArrayCopy; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.api.PointstoOptions; @@ -36,10 +35,10 @@ import jdk.vm.ci.code.BytecodePosition; /** - * Models the flow transfer of an {@link ArrayCopy} node which intrinsifies calls to - * System.arraycopy(). This flow registers itself as an observer for both the source and the - * destination. When either the source or the destination elements change the element flows from - * source are passed to destination. + * Models the flow transfer of an {@link org.graalvm.compiler.replacements.nodes.BasicArrayCopyNode} + * node which intrinsifies calls to System.arraycopy(). This flow registers itself as an observer + * for both the source and the destination. When either the source or the destination elements + * change the element flows from source are passed to destination. */ public class ArrayCopyTypeFlow extends TypeFlow { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/CloneTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/CloneTypeFlow.java index 305ddef2ec71..a2eeea1dd95d 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/CloneTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/CloneTypeFlow.java @@ -95,7 +95,7 @@ public void onObservedUpdate(PointsToAnalysis bb) { /* Nothing to be cloned if the input state is not a concrete type state. */ resultState = inputState.forNonNull(bb); } else { - resultState = inputState.typesStream() + resultState = inputState.typesStream(bb) .filter(t -> !currentState.containsType(t)) .map(type -> TypeState.forClone(bb, cloneSite, type, allocationContext)) .reduce(TypeState.forEmpty(), (s1, s2) -> TypeState.forUnion(bb, s1, s2)); @@ -115,7 +115,7 @@ public void update(PointsToAnalysis bb) { TypeState inputState = input.getState(); TypeState cloneState = this.getState(); - for (AnalysisType type : inputState.types()) { + for (AnalysisType type : inputState.types(bb)) { if (type.isArray()) { if (bb.analysisPolicy().aliasArrayTypeFlows()) { /* All arrays are aliased, no need to model the array clone operation. */ diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/DynamicNewInstanceTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/DynamicNewInstanceTypeFlow.java index 94684e7bfc2c..a3363ca105b5 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/DynamicNewInstanceTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/DynamicNewInstanceTypeFlow.java @@ -92,7 +92,7 @@ public void onObservedUpdate(PointsToAnalysis bb) { TypeState currentTypeState = getState(); /* Generate a heap object for every new incoming type. */ - TypeState resultState = newTypeState.typesStream() + TypeState resultState = newTypeState.typesStream(bb) .filter(t -> !currentTypeState.containsType(t)) .map(type -> TypeState.forAllocation(bb, allocationSite, type, allocationContext)) .reduce(TypeState.forEmpty(), (s1, s2) -> TypeState.forUnion(bb, s1, s2)); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java index 2157a3fb4b28..77c1ccd86672 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java @@ -93,7 +93,7 @@ import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.graph.MergeableState; import org.graalvm.compiler.phases.graph.PostOrderNodeIterator; -import org.graalvm.compiler.replacements.arraycopy.ArrayCopy; +import org.graalvm.compiler.replacements.nodes.BasicArrayCopyNode; import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode; import org.graalvm.compiler.replacements.nodes.MacroInvokable; import org.graalvm.compiler.replacements.nodes.ObjectClone; @@ -121,7 +121,6 @@ import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.nodes.AnalysisArraysCopyOfNode; import com.oracle.graal.pointsto.nodes.UnsafePartitionLoadNode; import com.oracle.graal.pointsto.nodes.UnsafePartitionStoreNode; import com.oracle.graal.pointsto.phases.InlineBeforeAnalysis; @@ -129,7 +128,6 @@ import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaKind; public class MethodTypeFlowBuilder { @@ -781,10 +779,7 @@ protected void node(FixedNode n) { } else { /* * Without precise type information the dynamic new instance node has to - * generate a heap object for each instantiated type. This means that the source - * flow for dynamic new instance is 'close to all instantiated' and will be - * reduced to abstract objects, unless - * BootImageAnalysisOptions.ReduceCloseToAllInstantiatedFlows is disabled. + * generate a heap object for each instantiated type. */ instanceType = bb.getObjectType(); instanceTypeBuilder = TypeFlowBuilder.create(bb, instanceType, AllInstantiatedTypeFlow.class, () -> { @@ -1123,8 +1118,8 @@ protected void node(FixedNode n) { AtomicReadAndWriteNode node = (AtomicReadAndWriteNode) n; modelUnsafeReadAndWriteFlow(node, node.object(), node.newValue(), node.offset()); - } else if (n instanceof ArrayCopy) { - ArrayCopy node = (ArrayCopy) n; + } else if (n instanceof BasicArrayCopyNode) { + BasicArrayCopyNode node = (BasicArrayCopyNode) n; TypeFlowBuilder srcBuilder = state.lookup(node.getSource()); TypeFlowBuilder dstBuilder = state.lookup(node.getDestination()); @@ -1171,10 +1166,6 @@ protected void node(FixedNode n) { state.add(node, wordToObjectBuilder); } - } else if (n instanceof AnalysisArraysCopyOfNode) { - AnalysisArraysCopyOfNode node = (AnalysisArraysCopyOfNode) n; - processArraysCopyOf(node, node.getOriginal(), node.getNewArrayType(), state); - } else if (n instanceof InvokeNode || n instanceof InvokeWithExceptionNode) { Invoke invoke = (Invoke) n; if (invoke.callTarget() instanceof MethodCallTargetNode) { @@ -1198,7 +1189,7 @@ protected void node(FixedNode n) { return cloneFlow; }); cloneBuilder.addObserverDependency(inputBuilder); - state.add(node.asNode(), cloneBuilder); + state.add(node.asFixedNode(), cloneBuilder); } else if (n instanceof MonitorEnterNode) { MonitorEnterNode node = (MonitorEnterNode) n; BytecodeLocation monitorLocation = BytecodeLocation.create(uniqueKey(node), methodFlow.getMethod()); @@ -1336,6 +1327,25 @@ private void processMethodInvocation(ValueNode invoke, InvokeKind invokeKind, in return actualReturn; }); + ObjectStamp stamp = (ObjectStamp) invoke.stamp(NodeView.DEFAULT); + if (stamp.nonNull() && !returnType.equals(stamp.type()) && returnType.isAssignableFrom(stamp.type())) { + /* + * If the invoke stamp has a more precise type than the return type use that to + * filter the returned values. This can happen for example for MacroInvokable + * nodes when more concrete stamp information can be inferred for example from + * parameter types. In that case the Graal graph optimizations may decide to + * remove a checkcast that would normally follow the invoke, so we need to + * introduce the filter to avoid loosing precision. + */ + TypeFlowBuilder filterBuilder = TypeFlowBuilder.create(bb, invoke, FilterTypeFlow.class, () -> { + FilterTypeFlow filterFlow = new FilterTypeFlow(invoke, (AnalysisType) stamp.type(), stamp.isExactType(), true, true); + methodFlow.addMiscEntry(filterFlow); + return filterFlow; + }); + filterBuilder.addUseDependency(actualReturnBuilder); + actualReturnBuilder = filterBuilder; + } + if (bb.strengthenGraalGraphs()) { typeFlowGraphBuilder.registerSinkBuilder(actualReturnBuilder); } @@ -1496,101 +1506,4 @@ protected NewInstanceTypeFlow createNewArrayTypeFlow(NewArrayNode node, Analysis protected void checkUnsafeOffset(@SuppressWarnings("unused") ValueNode base, @SuppressWarnings("unused") ValueNode offset) { } - protected void processArraysCopyOf(ValueNode node, ValueNode original, ValueNode newArrayType, TypeFlowsOfNodes state) { - TypeFlowBuilder originalArrayBuilder = state.lookup(original); - - Object key = uniqueKey(node); - BytecodeLocation newArrayLabel = bb.analysisPolicy().createAllocationSite(bb, key, methodFlow.getMethod()); - - /* - * Arrays.copyOf is essentially a dynamic new instance plus a System.arrayCopy. - */ - - /* - * First we determine the type of the new array and create a dynamic new instance flow to - * allocate it. - */ - TypeFlowBuilder newArrayTypeBuilder; - if (newArrayType == null) { - /* - * The type of the new array and that of the original are the same. The dynamic new - * instance flow will create a new heap object for each incoming type and for each - * different heap context. - */ - newArrayTypeBuilder = originalArrayBuilder; - } else { - /* - * The type of the new array and that of the original are different. The elements are - * copied from the original array but the type of the resulting objects are given by the - * new type. Both the original 'values' and the 'new type' are needed for a proper - * intercept when the analysis is context sensitive. - */ - newArrayTypeBuilder = getDynamicTypeFlow(node, newArrayType, true, state); - } - - TypeFlowBuilder newArrayBuilder = TypeFlowBuilder.create(bb, node, DynamicNewInstanceTypeFlow.class, () -> { - DynamicNewInstanceTypeFlow newArrayFlow = new DynamicNewInstanceTypeFlow(newArrayTypeBuilder.get(), bb.getObjectArrayType(), node, newArrayLabel); - methodFlow.addMiscEntry(newArrayFlow); - return newArrayFlow; - }); - - if (newArrayType != null && (newArrayType instanceof GetClassNode || newArrayType.isConstant())) { - newArrayBuilder.addObserverDependency(newArrayTypeBuilder); - } - - state.add(node, newArrayBuilder); - - /* - * Then we use an array copy type flow to propagate the elements type state from the - * original array into the copy. - */ - TypeFlowBuilder arrayCopyBuilder = TypeFlowBuilder.create(bb, node, ArrayCopyTypeFlow.class, () -> { - ArrayCopyTypeFlow arrayCopyFlow = new ArrayCopyTypeFlow(node, null, originalArrayBuilder.get(), newArrayBuilder.get()); - methodFlow.addMiscEntry(arrayCopyFlow); - return arrayCopyFlow; - }); - - arrayCopyBuilder.addObserverDependency(originalArrayBuilder); - arrayCopyBuilder.addObserverDependency(newArrayBuilder); - - /* Array copies must not be removed. */ - typeFlowGraphBuilder.registerSinkBuilder(arrayCopyBuilder); - } - - /** - * Get the type flow of a dynamic type. If the type results from a GetClassNode or a - * JavaConstant this method will return accurate type information. Otherwise it will return all - * instantiated types or, if it is an array, all instantiated array types. - */ - protected TypeFlowBuilder getDynamicTypeFlow(ValueNode node, ValueNode typeSource, boolean isArrayType, TypeFlowsOfNodes state) { - TypeFlowBuilder dynamicTypeBuilder; - if (typeSource instanceof GetClassNode) { - GetClassNode getClassNode = (GetClassNode) typeSource; - dynamicTypeBuilder = state.lookup(getClassNode.getObject()); - - } else if (typeSource.isConstant()) { - assert state.lookup(typeSource).getFlowClass() == SourceTypeFlow.class; - - Constant constant = typeSource.asJavaConstant(); - AnalysisType exactType = (AnalysisType) bb.getProviders().getConstantReflection().asJavaType(constant); - exactType.registerAsAllocated(node); - - dynamicTypeBuilder = TypeFlowBuilder.create(bb, node, SourceTypeFlow.class, () -> { - SourceTypeFlow dynamicTypeFlow = new SourceTypeFlow(node, TypeState.forExactType(bb, exactType, false)); - methodFlow.addMiscEntry(dynamicTypeFlow); - return dynamicTypeFlow; - }); - } else { - /* - * Without precise type information either the type flow corresponding to all - * instantiated object types or all instantiated array types will be returned. - */ - AnalysisType arrayType = isArrayType ? bb.getObjectArrayType() : bb.getObjectType(); - dynamicTypeBuilder = TypeFlowBuilder.create(bb, node, AllInstantiatedTypeFlow.class, () -> { - return arrayType.getTypeFlow(bb, false); - }); - } - - return dynamicTypeBuilder; - } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/TypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/TypeFlow.java index c39d8e98809c..74800ec5f649 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/TypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/TypeFlow.java @@ -39,6 +39,7 @@ import com.oracle.graal.pointsto.results.StaticAnalysisResultsBuilder; import com.oracle.graal.pointsto.typestate.PointsToStats; import com.oracle.graal.pointsto.typestate.TypeState; +import com.oracle.graal.pointsto.typestate.TypeStateUtils; import com.oracle.graal.pointsto.util.CompletionExecutor.DebugContextRunnable; import com.oracle.graal.pointsto.util.ConcurrentLightHashSet; import com.oracle.svm.util.ClassUtil; @@ -239,13 +240,9 @@ public boolean isAllInstantiated() { return this instanceof AllInstantiatedTypeFlow; } - public boolean isCloseToAllInstantiated(PointsToAnalysis bb) { - return this.getState().closeToAllInstantiated(bb); - } - public void setState(PointsToAnalysis bb, TypeState state) { assert !bb.extendedAsserts() || this instanceof InstanceOfTypeFlow || - state.verifyDeclaredType(declaredType) : "declaredType: " + declaredType.toJavaName(true) + " state: " + state; + state.verifyDeclaredType(bb, declaredType) : "declaredType: " + declaredType.toJavaName(true) + " state: " + state; this.state = state; } @@ -335,13 +332,13 @@ private boolean checkTypeState(PointsToAnalysis bb, TypeState before, TypeState */ return true; } - assert after.verifyDeclaredType(declaredType) : String.format("The type state of %s contains types that are not assignable from its declared type %s. " + + assert after.verifyDeclaredType(bb, declaredType) : String.format("The type state of %s contains types that are not assignable from its declared type %s. " + "%nState before: %s. %nState after: %s", format(false, true), declaredType.toJavaName(true), formatState(bb, before), formatState(bb, after)); return true; } private static String formatState(PointsToAnalysis bb, TypeState typeState) { - if (typeState.closeToAllInstantiated(bb)) { + if (TypeStateUtils.closeToAllInstantiated(bb, typeState)) { return "close to AllInstantiated"; } return typeState.toString(); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java index b670d5248c6f..ca169a1ccfe7 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java @@ -103,9 +103,8 @@ public class AnalysisType implements WrappedJavaType, OriginalClassProvider, Com */ private volatile ConcurrentHashMap> unsafeAccessedFields; - private static final AnalysisType[] EMPTY_ARRAY = {}; - - AnalysisType[] subTypes; + /** Immediate subtypes and this type itself. */ + private final Set subTypes; AnalysisType superClass; private final int id; @@ -143,7 +142,7 @@ public class AnalysisType implements WrappedJavaType, OriginalClassProvider, Com private final AnalysisType[] interfaces; /* isArray is an expensive operation so we eagerly compute it */ - private boolean isArray; + private final boolean isArray; private final int dimension; @@ -181,10 +180,24 @@ public enum UsageKind { */ } - subTypes = EMPTY_ARRAY; /* Ensure the super types as well as the component type (for arrays) is created too. */ superClass = universe.lookup(wrapped.getSuperclass()); interfaces = convertTypes(wrapped.getInterfaces()); + + subTypes = ConcurrentHashMap.newKeySet(); + addSubType(this); + + /* Build subtypes. */ + if (superClass != null) { + superClass.addSubType(this); + } + if (isInterface() && interfaces.length == 0) { + objectType.addSubType(this); + } + for (AnalysisType interf : interfaces) { + interf.addSubType(this); + } + if (isArray()) { this.componentType = universe.lookup(wrapped.getComponentType()); int dim = 0; @@ -462,7 +475,7 @@ private void markReachable() { */ registerAsAllocated(null); } - universe.hostVM.executor().execute(initializationTask); + ensureInitialized(); } } @@ -787,6 +800,15 @@ public ResolvedJavaType getSingleImplementor() { return this; } + /** Get the immediate subtypes, including this type itself. */ + public Set getSubTypes() { + return subTypes; + } + + private void addSubType(AnalysisType subType) { + this.subTypes.add(subType); + } + @Override public AnalysisType findLeastCommonAncestor(ResolvedJavaType otherType) { ResolvedJavaType subst = universe.substitutions.resolve(((AnalysisType) otherType).wrapped); @@ -813,7 +835,8 @@ public ResolvedJavaType getElementalType() { } public boolean hasSubTypes() { - return subTypes != null ? subTypes.length > 0 : false; + /* subTypes always includes this type itself. */ + return subTypes.size() > 1; } @Override diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java index 3131af28bfa6..2e5fb0c12ade 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java @@ -28,7 +28,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; @@ -161,7 +160,6 @@ public boolean sealed() { public void setAnalysisDataValid(boolean dataIsValid) { if (dataIsValid) { - buildSubTypes(); collectMethodImplementations(); } analysisDataValid = dataIsValid; @@ -399,7 +397,8 @@ public AnalysisMethod lookup(JavaMethod method) { } else if (result instanceof ResolvedJavaMethod) { return (AnalysisMethod) result; } - throw new UnsupportedFeatureException("Unresolved method found. Probably there are some compilation or classpath problems. " + method.format("%H.%n(%p)")); + throw new UnsupportedFeatureException("Unresolved method found: " + (method != null ? method.format("%H.%n(%p)") : "null") + + ". Probably there are some compilation or classpath problems. "); } @Override @@ -574,35 +573,6 @@ public Object replaceObject(Object source) { return destination; } - public void buildSubTypes() { - Map> allSubTypes = new HashMap<>(); - AnalysisType objectType = null; - for (AnalysisType type : getTypes()) { - allSubTypes.put(type, new HashSet<>()); - if (type.isInstanceClass() && type.getSuperclass() == null) { - objectType = type; - } - } - assert objectType != null; - - for (AnalysisType type : getTypes()) { - if (type.getSuperclass() != null) { - allSubTypes.get(type.getSuperclass()).add(type); - } - if (type.isInterface() && type.getInterfaces().length == 0) { - allSubTypes.get(objectType).add(type); - } - for (AnalysisType interf : type.getInterfaces()) { - allSubTypes.get(interf).add(type); - } - } - - for (AnalysisType type : getTypes()) { - Set subTypesSet = allSubTypes.get(type); - type.subTypes = subTypesSet.toArray(new AnalysisType[subTypesSet.size()]); - } - } - private void collectMethodImplementations() { for (AnalysisMethod method : methods.values()) { @@ -629,9 +599,12 @@ public static Set getMethodImplementations(BigBang bb, AnalysisM } private static boolean collectMethodImplementations(AnalysisMethod method, AnalysisType holder, Set implementations, boolean includeInlinedMethods) { - assert holder.subTypes != null : holder; boolean holderOrSubtypeInstantiated = holder.isInstantiated(); - for (AnalysisType subClass : holder.subTypes) { + for (AnalysisType subClass : holder.getSubTypes()) { + if (subClass.equals(holder)) { + /* Subtypes include the holder type itself. The holder is processed below. */ + continue; + } holderOrSubtypeInstantiated |= collectMethodImplementations(method, subClass, implementations, includeInlinedMethods); } @@ -654,21 +627,22 @@ private static boolean collectMethodImplementations(AnalysisMethod method, Analy return holderOrSubtypeInstantiated; } - public static Set getSubtypes(AnalysisType baseType) { - LinkedHashSet result = new LinkedHashSet<>(); - result.add(baseType); + /** + * Collect and returns *all* subtypes of this type, not only the immediate subtypes. The + * immediate sub-types are updated continuously as the universe is expanded and can be accessed + * using {@link AnalysisType#getSubTypes()}. + */ + public static Set getAllSubtypes(AnalysisType baseType) { + HashSet result = new HashSet<>(); collectSubtypes(baseType, result); return result; } private static void collectSubtypes(AnalysisType baseType, Set result) { - assert baseType.subTypes != null : baseType; - for (AnalysisType subType : baseType.subTypes) { - if (result.contains(subType)) { - continue; + for (AnalysisType subType : baseType.getSubTypes()) { + if (result.add(subType)) { + collectSubtypes(subType, result); } - result.add(subType); - collectSubtypes(subType, result); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/nodes/AnalysisArraysCopyOfNode.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/nodes/AnalysisArraysCopyOfNode.java deleted file mode 100644 index 73a9e41d9e52..000000000000 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/nodes/AnalysisArraysCopyOfNode.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.pointsto.nodes; - -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; - -import jdk.vm.ci.meta.ConstantReflectionProvider; -import org.graalvm.compiler.core.common.type.ObjectStamp; -import org.graalvm.compiler.core.common.type.Stamp; -import org.graalvm.compiler.core.common.type.StampFactory; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.FixedWithNextNode; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.spi.ArrayLengthProvider; - -@NodeInfo(size = SIZE_IGNORED, cycles = CYCLES_IGNORED) -public class AnalysisArraysCopyOfNode extends FixedWithNextNode implements ArrayLengthProvider { - public static final NodeClass TYPE = NodeClass.create(AnalysisArraysCopyOfNode.class); - - @Input ValueNode original; - @Input ValueNode newLength; - @OptionalInput ValueNode newArrayType; - - public AnalysisArraysCopyOfNode(@InjectedNodeParameter Stamp stamp, ValueNode original, ValueNode newLength) { - this(stamp, original, newLength, null); - } - - public AnalysisArraysCopyOfNode(@InjectedNodeParameter Stamp stamp, ValueNode original, ValueNode newLength, ValueNode newArrayType) { - super(TYPE, computeStamp(stamp)); - this.original = original; - this.newLength = newLength; - this.newArrayType = newArrayType; - } - - public ValueNode getOriginal() { - return original; - } - - public ValueNode getNewArrayType() { - return newArrayType; - } - - @Override - public ValueNode findLength(FindLengthMode mode, ConstantReflectionProvider constantReflection) { - return newLength; - } - - private static Stamp computeStamp(Stamp result) { - if (result instanceof ObjectStamp) { - return result.join(StampFactory.objectNonNull()); - } - return result; - } - -} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysis.java index 26a174339c99..5e6874405637 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysis.java @@ -258,7 +258,7 @@ protected void finishInlining(MethodScope is) { } killControlFlowNodes(inlineScope, invokeData.invokePredecessor.next()); assert invokeData.invokePredecessor.next() == null : "Successor must have been a fixed node created in the aborted scope, which is deleted now"; - invokeData.invokePredecessor.setNext(invokeData.invoke.asNode()); + invokeData.invokePredecessor.setNext(invokeData.invoke.asFixedNode()); if (inlineScope.exceptionPlaceholderNode != null) { assert invokeData.invoke instanceof InvokeWithExceptionNode; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/NoClassInitializationPlugin.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/NoClassInitializationPlugin.java similarity index 98% rename from substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/NoClassInitializationPlugin.java rename to substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/NoClassInitializationPlugin.java index c55749bf73c2..d7ebceed74da 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/NoClassInitializationPlugin.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/NoClassInitializationPlugin.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.hosted.phases; +package com.oracle.graal.pointsto.phases; import java.util.function.Supplier; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/SubstrateIntrinsicGraphBuilder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/SubstrateIntrinsicGraphBuilder.java index 935ebbf04767..5a0836569007 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/SubstrateIntrinsicGraphBuilder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/SubstrateIntrinsicGraphBuilder.java @@ -79,7 +79,7 @@ private FrameState getFrameState(ValueNode returnVal) { } @Override - public FrameState getIntrinsicReturnState(JavaKind returnKind, ValueNode retVal) { + public FrameState getInvocationPluginReturnState(JavaKind returnKind, ValueNode retVal) { return getFrameState(retVal); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/plugins/PointstoGraphBuilderPlugins.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/plugins/PointstoGraphBuilderPlugins.java index b4f27ef4cad5..5d61d9141561 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/plugins/PointstoGraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/plugins/PointstoGraphBuilderPlugins.java @@ -24,19 +24,15 @@ */ package com.oracle.graal.pointsto.plugins; -import java.util.Arrays; - import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.extended.GetClassNode; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; -import org.graalvm.compiler.replacements.nodes.BasicArrayCopyNode; +import org.graalvm.compiler.replacements.arraycopy.ArrayCopyNode; import org.graalvm.compiler.replacements.nodes.MacroNode.MacroParams; -import com.oracle.graal.pointsto.nodes.AnalysisArraysCopyOfNode; import com.oracle.graal.pointsto.nodes.AnalysisObjectCloneNode; import jdk.vm.ci.meta.JavaKind; @@ -44,36 +40,12 @@ public class PointstoGraphBuilderPlugins { - public static void registerArraysPlugins(InvocationPlugins plugins) { - Registration r = new Registration(plugins, Arrays.class).setAllowOverwrite(true); - - r.register2("copyOf", Object[].class, int.class, new InvocationPlugin() { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode original, ValueNode newLength) { - b.addPush(JavaKind.Object, new AnalysisArraysCopyOfNode(b.getInvokeReturnStamp(b.getAssumptions()).getTrustedStamp(), original, newLength)); - return true; - } - }); - - r.register3("copyOf", Object[].class, int.class, Class.class, new InvocationPlugin() { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode original, ValueNode newLength, ValueNode newObjectElementType) { - if (newObjectElementType instanceof GetClassNode || newObjectElementType.isConstant()) { - // We can infer the concrete type of the new array - b.addPush(JavaKind.Object, new AnalysisArraysCopyOfNode(b.getInvokeReturnStamp(b.getAssumptions()).getTrustedStamp(), original, newLength, newObjectElementType)); - return true; - } - return false; - } - }); - } - public static void registerSystemPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, System.class).setAllowOverwrite(true); r.register5("arraycopy", Object.class, int.class, Object.class, int.class, int.class, new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length) { - b.add(new BasicArrayCopyNode(BasicArrayCopyNode.TYPE, src, srcPos, dest, destPos, length, null, b.bci())); + b.add(new ArrayCopyNode(b.bci(), src, srcPos, dest, destPos, length)); return true; } }); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/AnalysisHeapHistogramPrinter.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/AnalysisHeapHistogramPrinter.java index 56a28c6cba81..c9b855de77cf 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/AnalysisHeapHistogramPrinter.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/AnalysisHeapHistogramPrinter.java @@ -35,6 +35,7 @@ import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.ObjectScanner; +import com.oracle.graal.pointsto.ObjectScanningObserver; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -54,12 +55,13 @@ private static void doPrint(PrintWriter out, BigBang bb) { System.out.println("Exhaustive heap scanning is disabled. The analysis heap histogram will not contain all instances of types: " + types); System.out.println("Exhaustive heap scanning can be turned on using -H:+ExhaustiveHeapScan."); } - AnalysisHeapHistogramPrinter printer = new AnalysisHeapHistogramPrinter(bb); + Map histogram = new HashMap<>(); + AnalysisHeapHistogramPrinter printer = new AnalysisHeapHistogramPrinter(bb, histogram); printer.scanBootImageHeapRoots(fieldComparator, positionComparator); - printer.printHistogram(out); + printHistogram(out, histogram); } - private void printHistogram(PrintWriter out) { + private static void printHistogram(PrintWriter out, Map histogram) { out.println("Heap histogram"); out.format("%8s %s %n", "Count", "Class"); @@ -67,36 +69,45 @@ private void printHistogram(PrintWriter out) { .forEach(entry -> out.format("%8d %8s %n", entry.getValue(), entry.getKey().toJavaName())); } - private final Map histogram = new HashMap<>(); - - private AnalysisHeapHistogramPrinter(BigBang bb) { - super(bb, null, new ReusableSet()); + private AnalysisHeapHistogramPrinter(BigBang bb, Map histogram) { + super(bb, null, new ReusableSet(), new ScanningObserver(bb, histogram)); } - @Override - protected void forScannedConstant(JavaConstant scannedValue, ScanReason reason) { - AnalysisType type = constantType(bb, scannedValue); - int count = histogram.getOrDefault(type, 0); - histogram.put(type, count + 1); - } + private static final class ScanningObserver implements ObjectScanningObserver { - @Override - public void forRelocatedPointerFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue) { - } + private final BigBang bb; + private final Map histogram; - @Override - public void forNullFieldValue(JavaConstant receiver, AnalysisField field) { - } + private ScanningObserver(BigBang bb, Map histogram) { + this.bb = bb; + this.histogram = histogram; + } - @Override - public void forNonNullFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue) { - } + @Override + public void forScannedConstant(JavaConstant scannedValue, ScanReason reason) { + AnalysisType type = constantType(bb, scannedValue); + int count = histogram.getOrDefault(type, 0); + histogram.put(type, count + 1); + } - @Override - public void forNullArrayElement(JavaConstant array, AnalysisType arrayType, int index) { - } + @Override + public void forRelocatedPointerFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue) { + } + + @Override + public void forNullFieldValue(JavaConstant receiver, AnalysisField field) { + } + + @Override + public void forNonNullFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue) { + } + + @Override + public void forNullArrayElement(JavaConstant array, AnalysisType arrayType, int index) { + } - @Override - public void forNonNullArrayElement(JavaConstant array, AnalysisType arrayType, JavaConstant elementConstant, AnalysisType elementType, int index) { + @Override + public void forNonNullArrayElement(JavaConstant array, AnalysisType arrayType, JavaConstant elementConstant, AnalysisType elementType, int index) { + } } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/AnalysisReporter.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/AnalysisReporter.java index 934bc68b935c..c1bd31aa2efe 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/AnalysisReporter.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/AnalysisReporter.java @@ -31,10 +31,12 @@ import org.graalvm.compiler.options.OptionValues; import com.oracle.graal.pointsto.BigBang; +import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.typestate.PointsToStats; import com.oracle.graal.pointsto.typestate.TypeState; +import com.oracle.graal.pointsto.typestate.TypeStateUtils; public class AnalysisReporter { public static void printAnalysisReports(String imageName, OptionValues options, String reportsPath, BigBang bb) { @@ -58,8 +60,8 @@ public static void printAnalysisReports(String imageName, OptionValues options, if (PointstoOptions.PrintSynchronizedAnalysis.getValue(options)) { TypeState allSynchronizedTypeState = bb.getAllSynchronizedTypeState(); - String typesString = allSynchronizedTypeState.closeToAllInstantiated(bb) ? "close to all instantiated" : // - StreamSupport.stream(allSynchronizedTypeState.types().spliterator(), false).map(AnalysisType::getName).collect(Collectors.joining(", ")); + String typesString = TypeStateUtils.closeToAllInstantiated((PointsToAnalysis) bb, allSynchronizedTypeState) ? "close to all instantiated" : // + StreamSupport.stream(allSynchronizedTypeState.types(bb).spliterator(), false).map(AnalysisType::getName).collect(Collectors.joining(", ")); System.out.println(); System.out.println("AllSynchronizedTypes"); System.out.println("Synchronized types #: " + allSynchronizedTypeState.typesCount()); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/AnalysisReportsOptions.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/AnalysisReportsOptions.java index 62b9e9d5780f..7bf1b7268946 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/AnalysisReportsOptions.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/AnalysisReportsOptions.java @@ -24,9 +24,12 @@ */ package com.oracle.graal.pointsto.reports; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionKey; +import static com.oracle.graal.pointsto.api.PointstoOptions.TrackAccessChain; + public class AnalysisReportsOptions { @Option(help = "Print analysis results statistics.")// @@ -38,6 +41,17 @@ public class AnalysisReportsOptions { @Option(help = "Print analysis call tree, a breadth-first tree reduction of the call graph.")// public static final OptionKey PrintAnalysisCallTree = new OptionKey<>(false); + @Option(help = "Print call edges with other analysis results statistics.")// + public static final OptionKey PrintCallEdges = new OptionKey(false) { + @Override + protected void onValueUpdate(EconomicMap, Object> values, Boolean oldValue, Boolean newValue) { + if (newValue) { + PrintAnalysisStatistics.update(values, true); + TrackAccessChain.update(values, true); + } + } + }; + @Option(help = "Print image object hierarchy.")// public static final OptionKey PrintImageObjectTree = new OptionKey<>(false); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/CallTreePrinter.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/CallTreePrinter.java index 1ee89f84013f..8f0c4d7ed3a6 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/CallTreePrinter.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/CallTreePrinter.java @@ -31,28 +31,46 @@ import static com.oracle.graal.pointsto.reports.ReportUtils.invokeComparator; import static com.oracle.graal.pointsto.reports.ReportUtils.methodComparator; +import java.io.IOException; import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Deque; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.Stream; import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.flow.InvokeTypeFlow; import com.oracle.graal.pointsto.meta.AnalysisMethod; import jdk.vm.ci.code.BytecodePosition; +import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; public final class CallTreePrinter { + public static final Pattern CAMEL_CASE_PATTERN = Pattern.compile( + "\\b[a-zA-Z]|[A-Z]|\\."); + public static void print(BigBang bb, String reportsPath, String reportName) { CallTreePrinter printer = new CallTreePrinter(bb); printer.buildCallTree(); @@ -65,6 +83,8 @@ public static void print(BigBang bb, String reportsPath, String reportName) { writer -> printer.printClasses(writer, false)); ReportUtils.report("list of used packages", reportsPath, "used_packages_" + reportName, "txt", writer -> printer.printClasses(writer, true)); + + printCsvFiles(printer.methodToNode, reportsPath, reportName); } interface Node { @@ -299,4 +319,275 @@ private static String packagePrefix(String name) { } return name.substring(0, lastDot); } + + private static void printCsvFiles(Map methodToNode, String reportsPath, String reportName) { + // Set virtual node at next available method id + final AtomicInteger virtualNodeId = new AtomicInteger(MethodNode.methodId); + + Set entryPointIds = new HashSet<>(); + Set nonVirtualNodes = new HashSet<>(); + Map, Integer> virtualNodes = new HashMap<>(); + + Map> directEdges = new HashMap<>(); + Map> virtualEdges = new HashMap<>(); + Map> overridenByEdges = new HashMap<>(); + + final Iterator iterator = methodToNode.values().stream().filter(n -> n.isEntryPoint).iterator(); + while (iterator.hasNext()) { + final MethodNode node = iterator.next(); + entryPointIds.add(node.id); + walkNodes(node, directEdges, virtualEdges, overridenByEdges, virtualNodes, nonVirtualNodes, virtualNodeId); + } + + toCsvFile("call tree for vm entry point", reportsPath, "csv_call_tree_vm", reportName, CallTreePrinter::printVMEntryPoint); + toCsvFile("call tree for methods", reportsPath, "csv_call_tree_methods", reportName, writer -> printMethodNodes(methodToNode.values(), writer)); + toCsvFile("call tree for virtual methods", reportsPath, "csv_call_tree_virtual_methods", reportName, writer -> printVirtualNodes(virtualNodes, writer)); + toCsvFile("call tree for entry points", reportsPath, "csv_call_tree_entry_points", reportName, writer -> printEntryPointIds(entryPointIds, writer)); + toCsvFile("call tree for direct edges", reportsPath, "csv_call_tree_direct_edges", reportName, writer -> printBciEdges(directEdges, writer)); + toCsvFile("call tree for overriden by edges", reportsPath, "csv_call_tree_override_by_edges", reportName, writer -> printNonBciEdges(overridenByEdges, writer)); + toCsvFile("call tree for virtual edges", reportsPath, "csv_call_tree_virtual_edges", reportName, writer -> printBciEdges(virtualEdges, writer)); + } + + private static void toCsvFile(String description, String reportsPath, String prefix, String reportName, Consumer reporter) { + final String name = prefix + "_" + reportName; + final String csvFile = ReportUtils.report(description, reportsPath, name, "csv", reporter); + final Path csvLink = Paths.get(reportsPath).resolve(prefix + ".csv"); + + if (Files.exists(csvLink, LinkOption.NOFOLLOW_LINKS)) { + try { + Files.delete(csvLink); + } catch (IOException e) { + // Ignore + } + } + + try { + Files.createSymbolicLink(csvLink, Paths.get(csvFile)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static void printVMEntryPoint(PrintWriter writer) { + writer.println(convertToCSV("Id", "Name")); + writer.println(convertToCSV("0", "VM")); + } + + private static void printMethodNodes(Collection methods, PrintWriter writer) { + writer.println(convertToCSV("Id", "Name", "Type", "Parameters", "Return", "Display")); + methods.stream() + .map(CallTreePrinter::methodNodeInfo) + .map(CallTreePrinter::convertToCSV) + .forEach(writer::println); + } + + private static List methodNodeInfo(MethodNode method) { + return resolvedJavaMethodInfo(method.id, method.method); + } + + private static void walkNodes(MethodNode methodNode, Map> directEdges, Map> virtualEdges, Map> overridenByEdges, + Map, Integer> virtualNodes, Set nonVirtualNodes, AtomicInteger virtualNodeId) { + for (InvokeNode invoke : methodNode.invokes) { + if (invoke.isDirectInvoke) { + if (invoke.callees.size() > 0) { + Node calleeNode = invoke.callees.get(0); + addDirectEdge(methodNode.id, invoke, calleeNode, directEdges, nonVirtualNodes); + if (calleeNode instanceof MethodNode) { + walkNodes((MethodNode) calleeNode, directEdges, virtualEdges, overridenByEdges, virtualNodes, nonVirtualNodes, virtualNodeId); + } + } + } else { + final int nodeId = addVirtualNode(invoke, virtualNodes, virtualNodeId); + addVirtualMethodEdge(methodNode.id, invoke, nodeId, virtualEdges); + for (Node calleeNode : invoke.callees) { + addOverridenByEdge(nodeId, calleeNode, overridenByEdges, nonVirtualNodes); + if (calleeNode instanceof MethodNode) { + walkNodes((MethodNode) calleeNode, directEdges, virtualEdges, overridenByEdges, virtualNodes, nonVirtualNodes, virtualNodeId); + } + } + } + } + } + + private static void addDirectEdge(int nodeId, InvokeNode invoke, Node calleeNode, Map> edges, Set nodes) { + Set nodeEdges = edges.computeIfAbsent(nodeId, k -> new HashSet<>()); + MethodNode methodNode = calleeNode instanceof MethodNode + ? (MethodNode) calleeNode + : ((MethodNodeReference) calleeNode).methodNode; + nodes.add(methodNode); + nodeEdges.add(new BciEndEdge(methodNode.id, bytecodeIndexes(invoke))); + } + + private static List bytecodeIndexes(InvokeNode node) { + return Stream.of(node.sourceReferences) + .map(source -> source.bci) + .collect(Collectors.toList()); + } + + private static int addVirtualNode(InvokeNode node, Map, Integer> virtualNodes, AtomicInteger virtualNodeId) { + final List virtualMethodInfo = virtualMethodInfo(node.targetMethod); + return virtualNodes.computeIfAbsent(virtualMethodInfo, k -> virtualNodeId.getAndIncrement()); + } + + private static void addVirtualMethodEdge(int startId, InvokeNode invoke, int endId, Map> edges) { + Set nodeEdges = edges.computeIfAbsent(startId, k -> new HashSet<>()); + nodeEdges.add(new BciEndEdge(endId, bytecodeIndexes(invoke))); + } + + private static void printVirtualNodes(Map, Integer> virtualNodes, PrintWriter writer) { + writer.println(convertToCSV("Id", "Name", "Type", "Parameters", "Return", "Display")); + virtualNodes.entrySet().stream() + .map(CallTreePrinter::virtualMethodAndIdInfo) + .map(CallTreePrinter::convertToCSV) + .forEach(writer::println); + } + + private static List virtualMethodAndIdInfo(Map.Entry, Integer> entry) { + final List methodInfo = entry.getKey(); + final List result = new ArrayList<>(methodInfo.size() + 1); + result.add(String.valueOf(entry.getValue())); + for (int i = 1; i < methodInfo.size(); i++) { + result.add(i, methodInfo.get(i)); + } + return result; + } + + private static void printEntryPointIds(Set entryPoints, PrintWriter writer) { + writer.println(convertToCSV("Id")); + entryPoints.forEach(writer::println); + } + + private static void addOverridenByEdge(int nodeId, Node calleeNode, Map> edges, Set nodes) { + Set nodeEdges = edges.computeIfAbsent(nodeId, k -> new HashSet<>()); + MethodNode methodNode = calleeNode instanceof MethodNode + ? (MethodNode) calleeNode + : ((MethodNodeReference) calleeNode).methodNode; + nodes.add(methodNode); + nodeEdges.add(methodNode.id); + } + + private static void printBciEdges(Map> edges, PrintWriter writer) { + final Set idEdges = edges.entrySet().stream() + .flatMap(entry -> entry.getValue().stream().map(endId -> new BciEdge(entry.getKey(), endId))) + .collect(Collectors.toSet()); + + writer.println(convertToCSV("StartId", "EndId", "BytecodeIndexes")); + idEdges.stream() + .map(edge -> convertToCSV(String.valueOf(edge.startId), String.valueOf(edge.endEdge.id), showBytecodeIndexes(edge.endEdge.bytecodeIndexes))) + .forEach(writer::println); + } + + private static String showBytecodeIndexes(List bytecodeIndexes) { + return bytecodeIndexes.stream() + .map(String::valueOf) + .collect(Collectors.joining("->")); + } + + private static void printNonBciEdges(Map> edges, PrintWriter writer) { + final Set idEdges = edges.entrySet().stream() + .flatMap(entry -> entry.getValue().stream().map(endId -> new NonBciEdge(entry.getKey(), endId))) + .collect(Collectors.toSet()); + + writer.println(convertToCSV("StartId", "EndId")); + idEdges.stream() + .map(edge -> convertToCSV(String.valueOf(edge.startId), String.valueOf(edge.endId))) + .forEach(writer::println); + } + + private static List virtualMethodInfo(AnalysisMethod method) { + return resolvedJavaMethodInfo(null, method); + } + + private static List resolvedJavaMethodInfo(Integer id, ResolvedJavaMethod method) { + // TODO method parameter types are opaque, but could in the future be split out and link + // together + // e.g. each method could BELONG to a type, and a method could have PARAMETER relationships + // with N types + // see https://neo4j.com/developer/guide-import-csv/#_converting_data_values_with_load_csv + // for examples + final String parameters = method.getSignature().getParameterCount(false) > 0 + ? method.format("%P").replace(",", "") + : "empty"; + + return Arrays.asList( + id == null ? null : Integer.toString(id), + method.getName(), + method.getDeclaringClass().toJavaName(true), + parameters, + method.getSignature().getReturnType(null).toJavaName(true), + display(method)); + } + + private static String display(ResolvedJavaMethod method) { + final ResolvedJavaType type = method.getDeclaringClass(); + final String typeName = type.toJavaName(true); + if (type.getJavaKind() == JavaKind.Object) { + List matchResults = new ArrayList<>(); + Matcher matcher = CAMEL_CASE_PATTERN.matcher(typeName); + while (matcher.find()) { + matchResults.add(matcher.toMatchResult().group()); + } + + return String.join("", matchResults) + "." + method.getName(); + } + + return typeName + "." + method.getName(); + } + + private static String convertToCSV(String... data) { + return String.join(",", data); + } + + private static String convertToCSV(List data) { + return String.join(",", data); + } + + private static final class NonBciEdge { + + final int startId; + final int endId; + + private NonBciEdge(int startId, int endId) { + this.startId = startId; + this.endId = endId; + } + } + + private static final class BciEdge { + final int startId; + final BciEndEdge endEdge; + + private BciEdge(int startId, BciEndEdge endEdge) { + this.startId = startId; + this.endEdge = endEdge; + } + } + + private static final class BciEndEdge { + final int id; + final List bytecodeIndexes; + + private BciEndEdge(int id, List bytecodeIndexes) { + this.id = id; + this.bytecodeIndexes = bytecodeIndexes; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + BciEndEdge endEdge = (BciEndEdge) o; + return id == endEdge.id && + bytecodeIndexes.equals(endEdge.bytecodeIndexes); + } + + @Override + public int hashCode() { + return Objects.hash(id, bytecodeIndexes); + } + } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ObjectTreePrinter.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ObjectTreePrinter.java index 08257afbc071..fafe5d3364ec 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ObjectTreePrinter.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ObjectTreePrinter.java @@ -47,6 +47,7 @@ import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.ObjectScanner; +import com.oracle.graal.pointsto.ObjectScanningObserver; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -70,9 +71,11 @@ private static void doPrint(PrintWriter out, BigBang bb) { System.out.println("Exhaustive heap scanning is disabled. The object tree will not contain all instances of types: " + types); System.out.println("Exhaustive heap scanning can be turned on using -H:+ExhaustiveHeapScan."); } - ObjectTreePrinter printer = new ObjectTreePrinter(bb); + /* Use linked hash map for predictable iteration order. */ + Map constantToNode = new LinkedHashMap<>(); + ObjectTreePrinter printer = new ObjectTreePrinter(bb, constantToNode); printer.scanBootImageHeapRoots(fieldComparator, positionComparator); - printer.printTypeHierarchy(out); + printer.printTypeHierarchy(out, constantToNode); } static class RootSource { @@ -285,7 +288,6 @@ public boolean matches(String input) { "com.ibm.icu.util.ULocale.nameCache*", "com.oracle.svm.core.option.RuntimeOptionsSupportImpl.set(String, Object)"}; - private final Map constantToNode; private final SimpleMatcher suppressTypeMatcher; private final SimpleMatcher expandTypeMatcher; private final SimpleMatcher defaultSuppressTypeMatcher; @@ -293,11 +295,8 @@ public boolean matches(String input) { private final SimpleMatcher expandRootMatcher; private final SimpleMatcher defaultSuppressRootMatcher; - private ObjectTreePrinter(BigBang bb) { - super(bb, null, new ReusableSet()); - - /* Use linked hash map for predictable iteration order. */ - this.constantToNode = new LinkedHashMap<>(); + private ObjectTreePrinter(BigBang bb, Map constantToNode) { + super(bb, null, new ReusableSet(), new ScanningObserver(bb, constantToNode)); OptionValues options = bb.getOptions(); @@ -310,76 +309,87 @@ private ObjectTreePrinter(BigBang bb) { this.defaultSuppressRootMatcher = new SimpleMatcher(suppressRootsDefault); } - @Override - public void forRelocatedPointerFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue) { - } + private static final class ScanningObserver implements ObjectScanningObserver { - @Override - public void forNullFieldValue(JavaConstant receiver, AnalysisField field) { - if (receiver == null) { - // static field - return; - } + private final BigBang bb; + private final Map constantToNode; - assert constantToNode.containsKey(receiver); + private ScanningObserver(BigBang bb, Map constantToNode) { + this.bb = bb; + this.constantToNode = constantToNode; + } - ObjectNode receiverNode = (ObjectNode) constantToNode.get(receiver); - receiverNode.addField(field, ObjectNodeBase.forNull()); - } + @Override + public void forRelocatedPointerFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue) { + } - @Override - public void forNonNullFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue) { + @Override + public void forNullFieldValue(JavaConstant receiver, AnalysisField field) { + if (receiver == null) { + // static field + return; + } - if (receiver == null) { - // static field - return; - } + assert constantToNode.containsKey(receiver); - if (constantToNode.containsKey(receiver) && constantToNode.containsKey(fieldValue)) { ObjectNode receiverNode = (ObjectNode) constantToNode.get(receiver); - ObjectNodeBase valueNode = constantToNode.get(fieldValue); - receiverNode.addField(field, valueNode); + receiverNode.addField(field, ObjectNodeBase.forNull()); } - } - @Override - public void forNullArrayElement(JavaConstant array, AnalysisType arrayType, int index) { - assert constantToNode.containsKey(array); + @Override + public void forNonNullFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue) { - ArrayObjectNode arrayNode = (ArrayObjectNode) constantToNode.get(array); - arrayNode.addElement(index, ObjectNodeBase.forNull()); - } + if (receiver == null) { + // static field + return; + } + + if (constantToNode.containsKey(receiver) && constantToNode.containsKey(fieldValue)) { + ObjectNode receiverNode = (ObjectNode) constantToNode.get(receiver); + ObjectNodeBase valueNode = constantToNode.get(fieldValue); + receiverNode.addField(field, valueNode); + } + } + + @Override + public void forNullArrayElement(JavaConstant array, AnalysisType arrayType, int index) { + assert constantToNode.containsKey(array); - @Override - public void forNonNullArrayElement(JavaConstant array, AnalysisType arrayType, JavaConstant elementConstant, AnalysisType elementType, int index) { - if (constantToNode.containsKey(array) && constantToNode.containsKey(elementConstant)) { ArrayObjectNode arrayNode = (ArrayObjectNode) constantToNode.get(array); - ObjectNodeBase valueNode = constantToNode.get(elementConstant); - arrayNode.addElement(index, valueNode); + arrayNode.addElement(index, ObjectNodeBase.forNull()); } - } - @Override - protected void forScannedConstant(JavaConstant scannedValue, ScanReason reason) { - JVMCIError.guarantee(scannedValue != null, "scannedValue is null"); - constantToNode.computeIfAbsent(scannedValue, c -> { - ObjectNodeBase node; - if (reason instanceof FieldScan) { - ResolvedJavaField field = ((FieldScan) reason).getField(); - if (field.isStatic()) { - node = ObjectNodeBase.fromConstant(bb, scannedValue, new RootSource(field)); + @Override + public void forNonNullArrayElement(JavaConstant array, AnalysisType arrayType, JavaConstant elementConstant, AnalysisType elementType, int index) { + if (constantToNode.containsKey(array) && constantToNode.containsKey(elementConstant)) { + ArrayObjectNode arrayNode = (ArrayObjectNode) constantToNode.get(array); + ObjectNodeBase valueNode = constantToNode.get(elementConstant); + arrayNode.addElement(index, valueNode); + } + } + + @Override + public void forScannedConstant(JavaConstant scannedValue, ScanReason reason) { + JVMCIError.guarantee(scannedValue != null, "scannedValue is null"); + constantToNode.computeIfAbsent(scannedValue, c -> { + ObjectNodeBase node; + if (reason instanceof FieldScan) { + ResolvedJavaField field = ((FieldScan) reason).getField(); + if (field.isStatic()) { + node = ObjectNodeBase.fromConstant(bb, scannedValue, new RootSource(field)); + } else { + node = ObjectNodeBase.fromConstant(bb, scannedValue); + } + } else if (reason instanceof MethodScan) { + ResolvedJavaMethod method = ((MethodScan) reason).getMethod(); + node = ObjectNodeBase.fromConstant(bb, scannedValue, new RootSource(method)); } else { node = ObjectNodeBase.fromConstant(bb, scannedValue); } - } else if (reason instanceof MethodScan) { - ResolvedJavaMethod method = ((MethodScan) reason).getMethod(); - node = ObjectNodeBase.fromConstant(bb, scannedValue, new RootSource(method)); - } else { - node = ObjectNodeBase.fromConstant(bb, scannedValue); - } - return node; - }); + return node; + }); + } } static String constantAsString(BigBang bb, JavaConstant constant) { @@ -453,7 +463,7 @@ private boolean suppressRoot(RootSource source) { return false; } - private void printTypeHierarchy(PrintWriter out) { + private void printTypeHierarchy(PrintWriter out, Map constantToNode) { out.println("Heap roots"); Iterator iterator = constantToNode.values().stream().filter(n -> n.isRoot()).iterator(); while (iterator.hasNext()) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ReportUtils.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ReportUtils.java index 8b743b0544a0..63e4a8218dfa 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ReportUtils.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ReportUtils.java @@ -75,10 +75,11 @@ public class ReportUtils { * @param extension the extension of the report * @param reporter a consumer that writes to a PrintWriter */ - public static void report(String description, String path, String name, String extension, Consumer reporter) { + public static String report(String description, String path, String name, String extension, Consumer reporter) { String fileName = timeStampedFileName(name, extension); Path reportDir = Paths.get(path); reportImpl(description, reportDir, fileName, reporter); + return fileName; } public static String timeStampedFileName(String name, String extension) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/StatisticsPrinter.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/StatisticsPrinter.java index 65ef2eb74e12..b9f6c3c4bd8c 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/StatisticsPrinter.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/StatisticsPrinter.java @@ -70,6 +70,11 @@ private void printStats(PrintWriter out) { beginObject(out); + if (AnalysisReportsOptions.PrintCallEdges.getValue(bb.getOptions())) { + int[] callEdges = getNumCallEdges(bb); + print(out, "total_call_edges", callEdges[0]); + print(out, "app_call_edges", callEdges[1]); + } print(out, "total_reachable_types", reachableTypes[0]); print(out, "app_reachable_types", reachableTypes[1]); print(out, "total_reachable_methods", reachableMethods[0]); @@ -108,6 +113,21 @@ public static void printLast(PrintWriter out, String key, long value) { out.format("%s\"%s\": %d%n", INDENT, key, value); } + private static int[] getNumCallEdges(BigBang bb) { + int callEdges = 0; + int appCallEdges = 0; + for (AnalysisMethod method : bb.getUniverse().getMethods()) { + if (method.isImplementationInvoked()) { + int callers = method.getCallers().size(); + callEdges += callers; + if (!isRuntimeLibraryType(method.getDeclaringClass())) { + appCallEdges += callers; + } + } + } + return new int[]{callEdges, appCallEdges}; + } + private static int[] getNumReachableTypes(BigBang bb) { int reachable = 0; int appReachable = 0; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/AbstractAnalysisResultsBuilder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/AbstractAnalysisResultsBuilder.java index d7f26876dc6c..6664431a1d04 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/AbstractAnalysisResultsBuilder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/AbstractAnalysisResultsBuilder.java @@ -127,7 +127,7 @@ private JavaTypeProfile cachedTypeProfile(JavaTypeProfile[] cache, int cacheIdx, private JavaTypeProfile createTypeProfile(TypeState typeState) { double probability = 1d / typeState.typesCount(); - JavaTypeProfile.ProfiledType[] pitems = typeState.typesStream() + JavaTypeProfile.ProfiledType[] pitems = typeState.typesStream(bb) .map(analysisType -> converter == null ? analysisType : converter.lookup(analysisType)) .sorted() .map(type -> new JavaTypeProfile.ProfiledType(type, probability)) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StaticAnalysisResultsBuilder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StaticAnalysisResultsBuilder.java index 46ac547d7f32..32ed909ecabf 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StaticAnalysisResultsBuilder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StaticAnalysisResultsBuilder.java @@ -47,6 +47,7 @@ import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.results.StaticAnalysisResults.BytecodeEntry; import com.oracle.graal.pointsto.typestate.TypeState; +import com.oracle.graal.pointsto.typestate.TypeStateUtils; import jdk.vm.ci.meta.JavaMethodProfile; import jdk.vm.ci.meta.JavaTypeProfile; @@ -162,8 +163,8 @@ public StaticAnalysisResults makeOrApplyResults(AnalysisMethod method) { .sorted(Comparator.comparingInt(m2 -> m2.getState().typesCount())) .forEach(monitorEnter -> { TypeState monitorEntryState = monitorEnter.getState(); - String typesString = monitorEntryState.closeToAllInstantiated(bb) ? "close to all instantiated" - : StreamSupport.stream(monitorEntryState.types().spliterator(), false).map(AnalysisType::getName).collect(Collectors.joining(", ")); + String typesString = TypeStateUtils.closeToAllInstantiated(bb, monitorEntryState) ? "close to all instantiated" + : StreamSupport.stream(monitorEntryState.types(bb).spliterator(), false).map(AnalysisType::getName).collect(Collectors.joining(", ")); StringBuilder strb = new StringBuilder(); strb.append("Location: "); String methodName = method.format("%h.%n(%p)"); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java index 9bf0bedcdb59..20ffe19ea353 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java @@ -82,7 +82,6 @@ import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.typestate.TypeState; - import com.oracle.svm.util.ImageBuildStatistics; import jdk.vm.ci.meta.JavaKind; @@ -284,7 +283,7 @@ public void simplify(Node n, SimplifierTool tool) { } private void handleInvoke(Invoke invoke, SimplifierTool tool) { - FixedNode node = invoke.asNode(); + FixedNode node = invoke.asFixedNode(); MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); InvokeTypeFlow invokeFlow = originalFlows.getInvokeFlow(invoke); @@ -391,7 +390,7 @@ private void unreachableInvoke(Invoke invoke, SimplifierTool tool) { InliningUtil.nonNullReceiver(invoke); } - makeUnreachable(invoke.asNode(), tool, () -> "method " + graph.method().format("%H.%n(%p)") + ", node " + invoke + + makeUnreachable(invoke.asFixedNode(), tool, () -> "method " + graph.method().format("%H.%n(%p)") + ", node " + invoke + ": empty list of callees for call to " + invoke.callTarget().targetMethod().format("%H.%n(%P)")); } @@ -496,7 +495,7 @@ private Stamp strengthenStampFromTypeFlow(ValueNode node, TypeFlow nodeFlow, * stamp is already more precise than the static analysis results. */ List typeStateTypes = new ArrayList<>(nodeTypeState.typesCount()); - for (AnalysisType typeStateType : nodeTypeState.types()) { + for (AnalysisType typeStateType : nodeTypeState.types(bb)) { if (oldType == null || (oldStamp.isExactType() ? oldType.equals(typeStateType) : oldType.isAssignableFrom(typeStateType))) { typeStateTypes.add(typeStateType); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/MultiTypeState.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/MultiTypeState.java index a684cfefe6fc..722f844d2ea4 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/MultiTypeState.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/MultiTypeState.java @@ -29,7 +29,6 @@ import java.util.Iterator; import com.oracle.graal.pointsto.BigBang; - import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.flow.context.object.AnalysisObject; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -37,7 +36,6 @@ public class MultiTypeState extends TypeState { - protected final PointsToAnalysis bb; /** The objects of this type state. */ protected final AnalysisObject[] objects; /** See {@link #getObjectTypeIds()}. */ @@ -58,7 +56,6 @@ public class MultiTypeState extends TypeState { /** Creates a new type state using the provided types bit set and objects. */ MultiTypeState(PointsToAnalysis bb, boolean canBeNull, int properties, BitSet typesBitSet, AnalysisObject... objects) { super(properties); - this.bb = bb; this.objects = objects; /* * Trim the typesBitSet to size eagerly. The typesBitSet is effectively immutable, i.e., no @@ -81,14 +78,13 @@ public class MultiTypeState extends TypeState { this.merged = false; assert typesCount > 1 : "Multi type state with single type."; assert objects.length > 1 : "Multi type state with single object."; - assert !bb.extendedAsserts() || checkObjects(); + assert !bb.extendedAsserts() || checkObjects(bb); PointsToStats.registerTypeState(bb, this); } /** Create a type state with the same content and a reversed canBeNull value. */ private MultiTypeState(PointsToAnalysis bb, boolean canBeNull, MultiTypeState other) { super(other.properties); - this.bb = bb; this.objects = other.objects; this.typesBitSet = other.typesBitSet; this.typesCount = other.typesCount; @@ -115,7 +111,7 @@ public int[] getObjectTypeIds() { return objectTypeIds; } - private boolean checkObjects() { + private boolean checkObjects(PointsToAnalysis bb) { assert bb.extendedAsserts(); for (int idx = 0; idx < objects.length - 1; idx++) { @@ -178,7 +174,7 @@ AnalysisType lastType() { * by way of bit set iteration. */ @Override - public Iterator typesIterator() { + public Iterator typesIterator(BigBang bb) { return new Iterator() { /** Initialize to the index of the first set bit. */ @@ -204,7 +200,7 @@ public boolean containsType(AnalysisType exactType) { } @Override - public TypeState exactTypeState(PointsToAnalysis unused, AnalysisType exactType) { + public TypeState exactTypeState(PointsToAnalysis bb, AnalysisType exactType) { if (containsType(exactType)) { AnalysisObject[] resultObjects = objectsArray(exactType); return new SingleTypeState(bb, canBeNull, bb.analysisPolicy().makeProperties(bb, resultObjects), resultObjects); @@ -214,7 +210,7 @@ public TypeState exactTypeState(PointsToAnalysis unused, AnalysisType exactType) } @Override - public TypeState forCanBeNull(PointsToAnalysis unused, boolean resultCanBeNull) { + public TypeState forCanBeNull(PointsToAnalysis bb, boolean resultCanBeNull) { if (resultCanBeNull == this.canBeNull()) { return this; } else { @@ -318,7 +314,7 @@ public final boolean canBeNull() { /** Note that the objects of this type state have been merged. */ @Override - public void noteMerge(PointsToAnalysis unused) { + public void noteMerge(PointsToAnalysis bb) { assert bb.analysisPolicy().isMergingEnabled(); if (!merged) { @@ -329,16 +325,6 @@ public void noteMerge(PointsToAnalysis unused) { } } - @Override - public boolean closeToAllInstantiated(BigBang unused) { - if (typesCount > 200) { - MultiTypeState allInstState = (MultiTypeState) bb.getAllInstantiatedTypes(); - return typesCount * 100L / allInstState.typesCount > 75; - } - - return false; - } - @Override public int hashCode() { int result = 1; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/PointsToStats.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/PointsToStats.java index 896ff2873c10..35abaad83559 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/PointsToStats.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/PointsToStats.java @@ -43,10 +43,10 @@ import java.util.function.Function; import java.util.stream.Collectors; -import com.oracle.graal.pointsto.BigBang; import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.nodes.ValueNode; +import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.flow.ActualReturnTypeFlow; import com.oracle.graal.pointsto.flow.AllInstantiatedTypeFlow; @@ -628,7 +628,7 @@ private static String formatType(AnalysisType type, boolean qualified) { } @SuppressWarnings("unused") - private static String asDetailedString(TypeState s) { + private static String asDetailedString(BigBang bb, TypeState s) { if (s.isEmpty()) { return ""; } @@ -637,7 +637,7 @@ private static String asDetailedString(TypeState s) { } String canBeNull = s.canBeNull() ? "null" : "!null"; - String types = s.typesStream().map(JavaType::getUnqualifiedName).sorted().collect(Collectors.joining(", ")); + String types = s.typesStream(bb).map(JavaType::getUnqualifiedName).sorted().collect(Collectors.joining(", ")); return canBeNull + ", " + types; } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/SingleTypeState.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/SingleTypeState.java index 1ab6c96127eb..7dd0cc8b1e84 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/SingleTypeState.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/SingleTypeState.java @@ -106,7 +106,7 @@ public AnalysisType exactType() { } @Override - protected Iterator typesIterator() { + protected Iterator typesIterator(BigBang bb) { return new Iterator() { boolean hasNext = true; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeState.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeState.java index 9aa59deafd57..43dde5bf1f3e 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeState.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeState.java @@ -33,8 +33,8 @@ import java.util.stream.StreamSupport; import com.oracle.graal.pointsto.AnalysisPolicy; -import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.BigBang; +import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.flow.context.AnalysisContext; import com.oracle.graal.pointsto.flow.context.BytecodeLocation; @@ -77,16 +77,16 @@ public int getProperties() { public abstract AnalysisType exactType(); /** Provides an iterator over the types. */ - protected abstract Iterator typesIterator(); + protected abstract Iterator typesIterator(BigBang bb); /** Provides an iterable for the types for easy "for-each loop" iteration. */ - public Iterable types() { - return this::typesIterator; + public Iterable types(BigBang bb) { + return () -> typesIterator(bb); } /** Provides a stream for the types. */ - public Stream typesStream() { - return StreamSupport.stream(types().spliterator(), false); + public Stream typesStream(BigBang bb) { + return StreamSupport.stream(types(bb).spliterator(), false); } /** Returns true if this type state contains the type, otherwise it returns false. */ @@ -240,9 +240,9 @@ public void noteMerge(@SuppressWarnings("unused") PointsToAnalysis bb) { */ public abstract TypeState exactTypeState(PointsToAnalysis bb, AnalysisType exactType); - public boolean verifyDeclaredType(AnalysisType declaredType) { + public boolean verifyDeclaredType(BigBang bb, AnalysisType declaredType) { if (declaredType != null) { - for (AnalysisType e : types()) { + for (AnalysisType e : types(bb)) { if (!declaredType.isAssignableFrom(e)) { return false; } @@ -251,14 +251,6 @@ public boolean verifyDeclaredType(AnalysisType declaredType) { return true; } - /** - * The {@link MultiTypeState} overrides this method and provides the proper test. All the other - * type states have only 0 or 1 types. - */ - public boolean closeToAllInstantiated(@SuppressWarnings("unused") BigBang bb) { - return false; - } - @Override public int hashCode() { return super.hashCode(); @@ -386,7 +378,7 @@ public static TypeState forContextInsensitiveTypeState(PointsToAnalysis bb, Type AnalysisObject[] objectsArray = new AnalysisObject[multiState.typesCount()]; int i = 0; - for (AnalysisType type : multiState.types()) { + for (AnalysisType type : multiState.types(bb)) { objectsArray[i++] = type.getContextInsensitiveAnalysisObject(); } /* @@ -437,7 +429,7 @@ public static TypeState forIntersection(PointsToAnalysis bb, TypeState s1, TypeS * All filtered types (s1) must be marked as instantiated to ensures that the filter state * (s2) has been updated before a type appears in the input, otherwise types can be missed. */ - assert !bb.extendedAsserts() || checkTypes(s1); + assert !bb.extendedAsserts() || checkTypes(bb, s1); if (s1.isEmpty()) { return s1; } else if (s1.isNull()) { @@ -463,7 +455,7 @@ public static TypeState forSubtraction(PointsToAnalysis bb, TypeState s1, TypeSt * All filtered types (s1) must be marked as instantiated to ensures that the filter state * (s2) has been updated before a type appears in the input, otherwise types can be missed. */ - assert !bb.extendedAsserts() || checkTypes(s1); + assert !bb.extendedAsserts() || checkTypes(bb, s1); if (s1.isEmpty()) { return s1; } else if (s1.isNull()) { @@ -484,8 +476,8 @@ public static TypeState forSubtraction(PointsToAnalysis bb, TypeState s1, TypeSt } } - private static boolean checkTypes(TypeState state) { - for (AnalysisType type : state.types()) { + private static boolean checkTypes(BigBang bb, TypeState state) { + for (AnalysisType type : state.types(bb)) { if (!type.isInstantiated()) { System.out.println("Processing a type not yet marked as instantiated: " + type.getName()); return false; @@ -1416,7 +1408,7 @@ public int typesCount() { } @Override - public Iterator typesIterator() { + public Iterator typesIterator(BigBang bb) { return Collections.emptyIterator(); } @@ -1507,7 +1499,7 @@ public int typesCount() { } @Override - public Iterator typesIterator() { + public Iterator typesIterator(BigBang bb) { return Collections.emptyIterator(); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeStateUtils.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeStateUtils.java index 84070f087493..32555ed4b2cc 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeStateUtils.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeStateUtils.java @@ -384,4 +384,12 @@ protected static BitSet set(BitSet bs1, int bitIndex) { return bsr; } + public static boolean closeToAllInstantiated(PointsToAnalysis bb, TypeState state) { + if (state.typesCount() > 200) { + MultiTypeState allInstState = (MultiTypeState) bb.getAllInstantiatedTypes(); + return state.typesCount() * 100L / allInstState.typesCount() > 75; + } + return false; + } + } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AnalysisError.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AnalysisError.java index b9f58533b894..8d59e33cd5a3 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AnalysisError.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AnalysisError.java @@ -125,6 +125,14 @@ private static String message(PointsToAnalysis bb, TypeFlow objectFlow, Bytec } } + public static class InterruptAnalysis extends AnalysisError { + private static final long serialVersionUID = 7126612141948542452L; + + InterruptAnalysis(String msg) { + super(msg); + } + } + public static TypeNotFoundError typeNotFound(ResolvedJavaType type) { throw new TypeNotFoundError(type); } @@ -166,4 +174,8 @@ public static void guarantee(boolean condition, String format, Object... args) { // Checkstyle: resume } } + + public static RuntimeException interruptAnalysis(String msg) { + throw new InterruptAnalysis(msg); + } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AnalysisFuture.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AnalysisFuture.java index 3d6ebb5b3e93..cceb2af8e7b0 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AnalysisFuture.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AnalysisFuture.java @@ -49,23 +49,22 @@ protected void setException(Throwable t) { throw new GraalError(t); } - /** Run the task and wait for it to complete, if necessary. */ - public void ensureDone() { + /** Run the task, wait for it to complete if necessary, then retrieve its result. */ + public V ensureDone() { try { /* - * If the task is not done yet trigger its execution and call get(), which waits for the - * computation to complete, if necessary. - * - * A task is "done" even if it failed with an exception. The exception is only reported - * when get() is invoked. That's why, to support this execution pattern without miss any - * exceptions, we report the error eagerly as a GraalError as soon as it is encountered. + * Trigger the task execution and call get(), which waits for the computation to + * complete, if necessary. + * + * A task is done even if it failed with an exception. The exception is only reported + * when get() is invoked. We report any error eagerly as a GraalError as soon as it is + * encountered. */ - if (!isDone()) { - run(); - get(); - } + run(); + return get(); } catch (InterruptedException | ExecutionException e) { - AnalysisError.shouldNotReachHere(e); + throw AnalysisError.shouldNotReachHere(e); } } + } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/CompletionExecutor.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/CompletionExecutor.java index 01d9cda71f3a..0f48c2eff19a 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/CompletionExecutor.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/CompletionExecutor.java @@ -62,14 +62,15 @@ private enum State { private final LongAdder postedOperations; private final LongAdder completedOperations; private final List postedBeforeStart; - private volatile CopyOnWriteArrayList exceptions = new CopyOnWriteArrayList<>(); + private final CopyOnWriteArrayList exceptions = new CopyOnWriteArrayList<>(); - public ExecutorService executorService; + private ExecutorService executorService; private final Runnable heartbeatCallback; - private BigBang bb; + private final BigBang bb; private Timing timing; private Object vmConfig; + private final Thread startingThread; public interface Timing { long getPrintIntervalNanos(); @@ -91,6 +92,7 @@ public CompletionExecutor(BigBang bb, ForkJoinPool forkJoin, Runnable heartbeatC postedOperations = new LongAdder(); completedOperations = new LongAdder(); postedBeforeStart = new ArrayList<>(); + startingThread = Thread.currentThread(); } public void init() { @@ -142,6 +144,11 @@ public void execute(DebugContextRunnable command) { case UNUSED: throw JVMCIError.shouldNotReachHere(); case BEFORE_START: + /* + * The postedBeforeStart list is not thread safe. Make sure that it is only updated + * from the same thread that created the executor. + */ + assert Thread.currentThread() == startingThread; postedBeforeStart.add(command); break; case STARTED: @@ -167,14 +174,14 @@ public void execute(DebugContextRunnable command) { } } - public void executeService(DebugContextRunnable command) { + private void executeService(DebugContextRunnable command) { executorService.execute(() -> { executeCommand(command); }); } @SuppressWarnings("try") - public void executeCommand(DebugContextRunnable command) { + private void executeCommand(DebugContextRunnable command) { bb.getHostVM().installInThread(vmConfig); long startTime = 0L; if (timing != null) { @@ -282,10 +289,6 @@ public boolean isStarted() { return state.get() == State.STARTED; } - public ExecutorService getExecutorService() { - return executorService; - } - public int parallelism() { if (executorService instanceof ForkJoinPool) { return ((ForkJoinPool) executorService).getParallelism(); @@ -300,6 +303,10 @@ public int poolSize() { return 1; } + public ExecutorService getExecutorService() { + return executorService; + } + public void setExecutorService(ExecutorService executorService) { this.executorService = executorService; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/GraalAccess.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/GraalAccess.java similarity index 89% rename from substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/GraalAccess.java rename to substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/GraalAccess.java index 295871bc5191..5cf94bbe3c41 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/GraalAccess.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/GraalAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.hosted.c; +package com.oracle.graal.pointsto.util; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.api.runtime.GraalJVMCICompiler; @@ -32,7 +32,10 @@ import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.runtime.JVMCI; -public class GraalAccess { +public final class GraalAccess { + + private GraalAccess() { + } public static TargetDescription getOriginalTarget() { return getGraalCapability(RuntimeProvider.class).getHostBackend().getTarget(); @@ -46,7 +49,7 @@ public static SnippetReflectionProvider getOriginalSnippetReflection() { return getGraalCapability(SnippetReflectionProvider.class); } - private static T getGraalCapability(Class clazz) { + public static T getGraalCapability(Class clazz) { GraalJVMCICompiler compiler = (GraalJVMCICompiler) JVMCI.getRuntime().getCompiler(); return compiler.getGraalRuntime().getCapability(clazz); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/PointsToOptionParser.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/PointsToOptionParser.java new file mode 100644 index 000000000000..fc7269d7251e --- /dev/null +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/PointsToOptionParser.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2021, Alibaba Group Holding Limited. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.pointsto.util; + +import static com.oracle.svm.common.option.CommonOptionParser.BooleanOptionFormat.PLUS_MINUS; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.function.Predicate; + +import org.graalvm.collections.EconomicMap; +import org.graalvm.compiler.options.OptionDescriptor; +import org.graalvm.compiler.options.OptionDescriptors; +import org.graalvm.compiler.options.OptionKey; +import org.graalvm.compiler.options.OptionValues; + +import com.oracle.svm.common.option.CommonOptionParser; +import com.oracle.svm.common.option.CommonOptionParser.BooleanOptionFormat; +import com.oracle.svm.common.option.CommonOptionParser.OptionParseResult; +import com.oracle.svm.common.option.UnsupportedOptionClassException; + +public final class PointsToOptionParser { + + private static PointsToOptionParser instance = new PointsToOptionParser(); + + private OptionValues optionValues = null; + private EconomicMap, Object> analysisValues = OptionValues.newOptionMap(); + private EconomicMap allAnalysisOptions = EconomicMap.create(); + + public static PointsToOptionParser getInstance() { + return instance; + } + + private PointsToOptionParser() { + ClassLoader appClassLoader = PointsToOptionParser.class.getClassLoader(); + CommonOptionParser.collectOptions(ServiceLoader.load(OptionDescriptors.class, appClassLoader), descriptor -> { + String name = descriptor.getName(); + if (descriptor.getOptionKey() != null) { + OptionDescriptor existing = allAnalysisOptions.put(name, descriptor); + if (existing != null) { + AnalysisError.shouldNotReachHere("Option name \"" + name + "\" has multiple definitions: " + existing.getLocation() + " and " + descriptor.getLocation()); + } + } + }); + } + + public void setOptionValue(OptionKey optionKey, Object value) { + if (optionValues == null) { + parse(new String[0]); + } + optionKey.update((EconomicMap, Object>) optionValues.getMap(), value); + } + + public OptionValues parse(String[] args) { + List remainingArgs = new ArrayList<>(); + Set errors = new HashSet<>(); + for (String arg : args) { + boolean isAnalysisOption = false; + isAnalysisOption |= parseOption(CommonOptionParser.HOSTED_OPTION_PREFIX, allAnalysisOptions, analysisValues, PLUS_MINUS, errors, arg, System.out); + if (!isAnalysisOption) { + remainingArgs.add(arg); + } + } + optionValues = new OptionValues(analysisValues); + if (!remainingArgs.isEmpty()) { + AnalysisError.interruptAnalysis(String.format("Unknown options: %s", Arrays.toString(remainingArgs.toArray(new String[0])))); + } + if (!errors.isEmpty()) { + StringBuilder errMsg = new StringBuilder("Option format error:\n"); + for (String err : errors) { + errMsg.append(err).append("\n"); + } + AnalysisError.interruptAnalysis(errMsg.toString()); + } + return optionValues; + } + + private static boolean parseOption(String optionPrefix, EconomicMap options, EconomicMap, Object> valuesMap, + BooleanOptionFormat booleanOptionFormat, Set errors, String arg, PrintStream out) { + if (!arg.startsWith(optionPrefix)) { + return false; + } + try { + Predicate> optionKeyPredicate = optionKey -> { + Class clazz = optionKey.getClass(); + // All classes from com.oracle.graal.pointsto.api.PointstoOptions are taken as + // non-hosted options. + if (clazz.getName().startsWith("com.oracle.graal.pointsto.api.PointstoOptions")) { + return false; + } + if (!clazz.equals(OptionKey.class) && OptionKey.class.isAssignableFrom(clazz)) { + return true; + } else { + return false; + } + }; + OptionParseResult optionParseResult = CommonOptionParser.parseOption(options, optionKeyPredicate, arg.substring(optionPrefix.length()), valuesMap, + optionPrefix, booleanOptionFormat); + if (optionParseResult.printFlags() || optionParseResult.printFlagsWithExtraHelp()) { + CommonOptionParser.printFlags(d -> optionParseResult.matchesFlags(d, true), options, optionPrefix, out, optionParseResult.printFlagsWithExtraHelp()); + System.out.println("Abort analysis due to print flags are requested"); + System.exit(1); + } + if (!optionParseResult.isValid()) { + errors.add(optionParseResult.getError()); + } + } catch (UnsupportedOptionClassException e) { + AnalysisError.shouldNotReachHere(e); + } + return true; + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/BasicProgbitsSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/BasicProgbitsSectionImpl.java index f0269d2e1447..b74d2177a943 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/BasicProgbitsSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/BasicProgbitsSectionImpl.java @@ -113,21 +113,21 @@ public List

    getElements() { } @Override - public void markRelocationSite(int offset, RelocationKind k, String symbolName, boolean useImplicitAddend, Long explicitAddend) { - ((RelocatableSectionImpl) getElement()).markRelocationSite(offset, ByteBuffer.wrap(getContent()).order(getOwner().getByteOrder()), k, symbolName, useImplicitAddend, - explicitAddend); + public void markRelocationSite(int offset, RelocationKind k, String symbolName, long addend) { + ((RelocatableSectionImpl) getElement()).markRelocationSite(offset, ByteBuffer.wrap(getContent()).order(getOwner().getByteOrder()), k, symbolName, + addend); } @Override - public final void markRelocationSite(int offset, ByteBuffer bb, RelocationKind k, String symbolName, boolean useImplicitAddend, Long explicitAddend) { + public final void markRelocationSite(int offset, ByteBuffer bb, RelocationKind k, String symbolName, long addend) { assert getContent() == null || bb.array() == getContent(); - ((RelocatableSectionImpl) getElement()).markRelocationSite(offset, bb, k, symbolName, useImplicitAddend, explicitAddend); + ((RelocatableSectionImpl) getElement()).markRelocationSite(offset, bb, k, symbolName, addend); } @Override - public Element getOrCreateRelocationElement(boolean useImplicitAddend) { + public Element getOrCreateRelocationElement(long addend) { // FIXME: This looks suspicious: turning an Element back into an Impl? - return ((RelocatableSectionImpl) getElement()).getOrCreateRelocationElement(useImplicitAddend); + return ((RelocatableSectionImpl) getElement()).getOrCreateRelocationElement(addend); } @Override diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index 3c879bec2cb9..5484b9f97b49 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -358,11 +358,6 @@ public static int getRelocationSize(RelocationKind kind) { * Interface implemented by objects implementing a specific relocation method and size. */ public interface RelocationMethod { - - boolean canUseImplicitAddend(); - - boolean canUseExplicitAddend(); - /* * If we were implementing a linker, we'd have a method something like * @@ -412,10 +407,9 @@ public interface RelocatableSectionImpl extends ElementImpl { * @param k the kind of fixup to be applied * @param symbolName the name of the symbol whose value is used to compute the fixed-up * bytes - * @param useImplicitAddend whether the current bytes are to be used as an addend - * @param explicitAddend a full-width addend, or null if useImplicitAddend is true + * @param addend a full-width addend, or 0 if unneeded */ - void markRelocationSite(int offset, ByteBuffer bb, RelocationKind k, String symbolName, boolean useImplicitAddend, Long explicitAddend); + void markRelocationSite(int offset, ByteBuffer bb, RelocationKind k, String symbolName, long addend); /** * Force the creation of a relocation section/element for this section, and return it. This @@ -423,13 +417,12 @@ public interface RelocatableSectionImpl extends ElementImpl { * which leads to unpredictable results (e.g. not appearing in the ELF SHT, if the SHT was * written before the section was created). * - * @param useImplicitAddend whether the relocation section of interest is for implicit - * addends + * @param addend whether a full-width addend, or 0 if unneeded * * @return the element which will hold relocation records (of the argument-specified kind) * for this section */ - Element getOrCreateRelocationElement(boolean useImplicitAddend); + Element getOrCreateRelocationElement(long addend); } /** @@ -446,7 +439,7 @@ public interface ProgbitsSectionImpl extends RelocatableSectionImpl { * passed a buffer. It uses the byte array accessed by {@link #getContent} and * {@link #setContent}. */ - void markRelocationSite(int offset, RelocationKind k, String symbolName, boolean useImplicitAddend, Long explicitAddend); + void markRelocationSite(int offset, RelocationKind k, String symbolName, long addend); } public interface NobitsSectionImpl extends ElementImpl { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/StringSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/StringSectionImpl.java index fc262713ac3a..a96531f0f1a2 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/StringSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/StringSectionImpl.java @@ -119,17 +119,17 @@ public StringSectionImpl() { */ @Override - public Element getOrCreateRelocationElement(boolean useImplicitAddend) { + public Element getOrCreateRelocationElement(long addend) { throw new UnsupportedOperationException("can't mark relocaction sites in string section"); } @Override - public void markRelocationSite(int offset, RelocationKind k, String symbolName, boolean useImplicitAddend, Long explicitAddend) { + public void markRelocationSite(int offset, RelocationKind k, String symbolName, long addend) { throw new UnsupportedOperationException("can't mark relocaction sites in string section"); } @Override - public void markRelocationSite(int offset, ByteBuffer bb, RelocationKind k, String symbolName, boolean useImplicitAddend, Long explicitAddend) { + public void markRelocationSite(int offset, ByteBuffer bb, RelocationKind k, String symbolName, long addend) { throw new UnsupportedOperationException("can't mark relocaction sites in string section"); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFMachine.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFMachine.java index c7b69cf630f8..4e1aa9456449 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFMachine.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFMachine.java @@ -33,12 +33,6 @@ * ELF machine type (incomplete). Each machine type also defines its set of relocation types. */ public enum ELFMachine/* implements Integral */ { - NONE { - @Override - Class> relocationTypes() { - return ELFDummyRelocation.class; - } - }, X86_64 { @Override Class> relocationTypes() { @@ -136,16 +130,13 @@ public static ELFRelocationMethod getRelocation(ELFMachine m, RelocationKind k) } default: - case NONE: - return ELFDummyRelocation.R_NONE; + throw new IllegalStateException("unknown ELF machine type"); } } // TODO: use explicit enum values public static ELFMachine from(int m) { switch (m) { - case 0: - return NONE; case 0x3E: return X86_64; case 0xB7: @@ -156,9 +147,7 @@ public static ELFMachine from(int m) { } public short toShort() { - if (this == NONE) { - return 0; - } else if (this == AArch64) { + if (this == AArch64) { return 0xB7; } else if (this == X86_64) { return 0x3E; @@ -176,25 +165,6 @@ public static ELFMachine getSystemNativeValue() { } } -enum ELFDummyRelocation implements ELFRelocationMethod { - R_NONE; - - @Override - public boolean canUseExplicitAddend() { - return true; - } - - @Override - public boolean canUseImplicitAddend() { - return true; - } - - @Override - public long toLong() { - return ordinal(); - } -} - enum ELFX86_64Relocation implements ELFRelocationMethod { // These are all named R_X86_64_... in elf.h, // but we just use R_... to keep it short. @@ -245,19 +215,6 @@ enum ELFX86_64Relocation implements ELFRelocationMethod { assert R_COUNT.ordinal() == 39; } - /* - * x86-64 relocs always use explicit addends. - */ - @Override - public boolean canUseExplicitAddend() { - return true; - } - - @Override - public boolean canUseImplicitAddend() { - return false; - } - @Override public long toLong() { return ordinal(); @@ -398,16 +355,6 @@ enum ELFAArch64Relocation implements ELFRelocationMethod { this.code = code; } - @Override - public boolean canUseImplicitAddend() { - return false; - } - - @Override - public boolean canUseExplicitAddend() { - return true; - } - @Override public long toLong() { return code; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index 9e696a1bbaa7..ab705f9717f6 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -35,6 +35,9 @@ import java.util.Map; import java.util.Set; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; + import com.oracle.objectfile.BuildDependency; import com.oracle.objectfile.ElementImpl; import com.oracle.objectfile.LayoutDecision; @@ -45,15 +48,13 @@ import com.oracle.objectfile.debuginfo.DebugInfoProvider; import com.oracle.objectfile.elf.dwarf.DwarfARangesSectionImpl; import com.oracle.objectfile.elf.dwarf.DwarfAbbrevSectionImpl; +import com.oracle.objectfile.elf.dwarf.DwarfDebugInfo; import com.oracle.objectfile.elf.dwarf.DwarfFrameSectionImpl; import com.oracle.objectfile.elf.dwarf.DwarfInfoSectionImpl; import com.oracle.objectfile.elf.dwarf.DwarfLineSectionImpl; -import com.oracle.objectfile.elf.dwarf.DwarfDebugInfo; import com.oracle.objectfile.elf.dwarf.DwarfStrSectionImpl; import com.oracle.objectfile.io.AssemblyBuffer; import com.oracle.objectfile.io.OutputAssembler; -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.Platform; /** * Represents an ELF object file (of any kind: relocatable, shared library, executable, core, ...). @@ -469,9 +470,9 @@ public class ELFHeader extends ObjectFile.Header { */ class Struct { - IdentStruct ident = new IdentStruct(); - ELFType type; - ELFMachine machine; + final IdentStruct ident; + final ELFType type; + final ELFMachine machine; int version; long entry; long phoff; @@ -484,10 +485,10 @@ class Struct { short shnum; short shstrndx; - Struct() { + Struct(ELFType type, ELFMachine machine) { ident = new IdentStruct(); - type = ELFType.NONE; - machine = ELFMachine.NONE; + this.type = type; + this.machine = machine; } /** @@ -618,7 +619,8 @@ public Iterable getDependencies(Map public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { // we serialize ourselves by writing a Struct to a bytebuffer OutputAssembler oa = AssemblyBuffer.createOutputAssembler(getDataEncoding().toByteOrder()); - Struct contents = new Struct(); // also creates ident struct, which we need to populate + /* Also creates ident struct, which we need to populate. */ + Struct contents = new Struct(getType(), getMachine()); // don't assign magic -- its default value is correct contents.ident.fileClass = getFileClass(); @@ -626,8 +628,6 @@ public byte[] getOrDecideContent(Map alreadyDecided, contents.ident.version = getVersion(); contents.ident.osabi = getOsAbi(); contents.ident.abiVersion = (char) getAbiVersion(); - contents.type = getType(); - contents.machine = getMachine(); contents.version = getVersion(); contents.entry = 0; contents.shoff = (int) alreadyDecided.get(sht).getDecidedValue(LayoutDecision.Kind.OFFSET); @@ -668,7 +668,7 @@ public int getOrDecideOffset(Map alreadyDecided, int @Override public int getOrDecideSize(Map alreadyDecided, int sizeHint) { - int size = (new Struct()).getWrittenSize(); + int size = (new Struct(getType(), getMachine())).getWrittenSize(); assert sizeHint == -1 || sizeHint == size; return size; } @@ -1193,13 +1193,19 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { * decision set and causes an NPE during reloc section write. So we need to create the * relevant reloc sections here in advance. */ - elfStrSectionImpl.getOrCreateRelocationElement(false); - elfAbbrevSectionImpl.getOrCreateRelocationElement(false); - frameSectionImpl.getOrCreateRelocationElement(false); - elfInfoSectionImpl.getOrCreateRelocationElement(false); - elfARangesSectionImpl.getOrCreateRelocationElement(false); - elfLineSectionImpl.getOrCreateRelocationElement(false); + elfStrSectionImpl.getOrCreateRelocationElement(0); + elfAbbrevSectionImpl.getOrCreateRelocationElement(0); + frameSectionImpl.getOrCreateRelocationElement(0); + elfInfoSectionImpl.getOrCreateRelocationElement(0); + elfARangesSectionImpl.getOrCreateRelocationElement(0); + elfLineSectionImpl.getOrCreateRelocationElement(0); /* Ok now we can populate the debug info model. */ dwarfSections.installDebugInfo(debugInfoProvider); } + + @SuppressWarnings("unused") + static boolean useExplicitAddend(long addend) { + // For now, we are always using explicit addends + return true; + } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFProgbitsSection.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFProgbitsSection.java index c08176850a51..d06775fb809a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFProgbitsSection.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFProgbitsSection.java @@ -69,7 +69,7 @@ public void setContent(byte[] c) { } @Override - public void markRelocationSite(int offset, ObjectFile.RelocationKind k, String symbolName, boolean useImplicitAddend, Long explicitAddend) { - markRelocationSite(offset, ByteBuffer.wrap(getContent()).order(getOwner().getByteOrder()), k, symbolName, useImplicitAddend, explicitAddend); + public void markRelocationSite(int offset, ObjectFile.RelocationKind k, String symbolName, long addend) { + markRelocationSite(offset, ByteBuffer.wrap(getContent()).order(getOwner().getByteOrder()), k, symbolName, addend); } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java index 538a2bf4352e..52a10326b91d 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java @@ -108,6 +108,19 @@ int getWrittenSize() { interface ELFRelocationMethod extends RelocationMethod { + /* + * For now, ELF relocations are always using explicit addends. This can change in the + * future. + */ + + default boolean canUseImplicitAddend() { + return false; + } + + default boolean canUseExplicitAddend() { + return true; + } + long toLong(); } @@ -172,8 +185,8 @@ public int hashCode() { } } - public Entry addEntry(ELFSection s, long offset, ELFRelocationMethod t, ELFSymtab.Entry sym, Long explicitAddend) { - if (explicitAddend != null) { + void addEntry(ELFSection s, long offset, ELFRelocationMethod t, ELFSymtab.Entry sym, long addend) { + if (ELFObjectFile.useExplicitAddend(addend)) { if (!t.canUseExplicitAddend()) { throw new IllegalArgumentException("cannot use relocation method " + t + " with explicit addends"); } @@ -181,6 +194,7 @@ public Entry addEntry(ELFSection s, long offset, ELFRelocationMethod t, ELFSymta throw new IllegalStateException("cannot create relocation with addend in .rel section"); } } else { + // use implicit addend if (!t.canUseImplicitAddend()) { throw new IllegalArgumentException("cannot use relocation method " + t + " with implicit addends"); } @@ -188,8 +202,7 @@ public Entry addEntry(ELFSection s, long offset, ELFRelocationMethod t, ELFSymta throw new IllegalStateException("cannot create relocation without addend in .rela section"); } } - long addend = (explicitAddend != null) ? explicitAddend : 0L; - return entries.computeIfAbsent(new Entry(s, offset, t, sym, addend), Function.identity()); + entries.computeIfAbsent(new Entry(s, offset, t, sym, addend), Function.identity()); } public boolean isDynamic() { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFUserDefinedSection.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFUserDefinedSection.java index 6d3f29be036b..e8a3df3e4444 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFUserDefinedSection.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFUserDefinedSection.java @@ -126,36 +126,35 @@ public LayoutDecisionMap getDecisions(LayoutDecisionMap copyingIn) { } @Override - public Element getOrCreateRelocationElement(boolean useImplicitAddend) { + public Element getOrCreateRelocationElement(long addend) { ELFSymtab syms = (ELFSymtab) getOwner().elementForName(".symtab"); if (syms == null) { throw new IllegalStateException("cannot create a relocation section without corresponding symtab"); } - boolean withExplicitAddends = !useImplicitAddend; - ELFRelocationSection rs = withExplicitAddends ? rela : rel; - if (rs == null) { - // we have to create the section if it doesn't exist - rs = getOwner().getOrCreateRelocSection(this, syms, withExplicitAddends); - assert rs != null; - if (withExplicitAddends) { - rela = rs; - } else { - rel = rs; + + if (ELFObjectFile.useExplicitAddend(addend)) { + if (rela == null) { + rela = getOwner().getOrCreateRelocSection(this, syms, true); + assert rela != null; + } + return rela; + } else { + // use implicit addend + if (rel == null) { + rel = getOwner().getOrCreateRelocSection(this, syms, false); + assert rel != null; } + return rel; } - return rs; } @Override - public void markRelocationSite(int offset, ByteBuffer bb, ObjectFile.RelocationKind k, String symbolName, boolean useImplicitAddend, Long explicitAddend) { - if (useImplicitAddend != (explicitAddend == null)) { - throw new IllegalArgumentException("must have either an explicit or implicit addend"); - } + public void markRelocationSite(int offset, ByteBuffer bb, ObjectFile.RelocationKind k, String symbolName, long addend) { ELFSymtab syms = (ELFSymtab) getOwner().elementForName(".symtab"); - ELFRelocationSection rs = (ELFRelocationSection) getOrCreateRelocationElement(useImplicitAddend); + ELFRelocationSection rs = (ELFRelocationSection) getOrCreateRelocationElement(addend); assert symbolName != null; ELFSymtab.Entry ent = syms.getSymbol(symbolName); assert ent != null; - rs.addEntry(this, offset, ELFMachine.getRelocation(getOwner().getMachine(), k), ent, explicitAddend); + rs.addEntry(this, offset, ELFMachine.getRelocation(getOwner().getMachine(), k), ent, addend); } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java index 26916fc8cec1..e8ab5db09050 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java @@ -277,8 +277,8 @@ public void createContent() { * *
  • DW_AT_use_UTF8 : ... DW_FORM_flag * - *
  • DW_AT_stmt_list : .. DW_FORM_data4 n.b only for abbrev-code == - * class_unit1 + *
  • DW_AT_stmt_list : .. DW_FORM_sec_offset n.b only for abbrev-code + * == class_unit1 * * * @@ -886,7 +886,7 @@ private int writeClassUnitAbbrev(@SuppressWarnings("unused") DebugContext contex } if (abbrevCode == DwarfDebugInfo.DW_ABBREV_CODE_class_unit1) { pos = writeAttrType(DwarfDebugInfo.DW_AT_stmt_list, buffer, pos); - pos = writeAttrForm(DwarfDebugInfo.DW_FORM_data4, buffer, pos); + pos = writeAttrForm(DwarfDebugInfo.DW_FORM_sec_offset, buffer, pos); } /* * Now terminate. diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java index 8fcad6f32b1d..9adc3617678a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java @@ -169,11 +169,12 @@ public class DwarfDebugInfo extends DebugInfoBase { @SuppressWarnings("unused") public static final int DW_FORM_data8 = 0x7; @SuppressWarnings("unused") private static final int DW_FORM_string = 0x8; @SuppressWarnings("unused") public static final int DW_FORM_block1 = 0x0a; + public static final int DW_FORM_ref_addr = 0x10; @SuppressWarnings("unused") public static final int DW_FORM_ref1 = 0x11; @SuppressWarnings("unused") public static final int DW_FORM_ref2 = 0x12; @SuppressWarnings("unused") public static final int DW_FORM_ref4 = 0x13; @SuppressWarnings("unused") public static final int DW_FORM_ref8 = 0x14; - public static final int DW_FORM_ref_addr = 0x10; + public static final int DW_FORM_sec_offset = 0x17; public static final int DW_FORM_data1 = 0x0b; public static final int DW_FORM_flag = 0xc; public static final int DW_FORM_strp = 0xe; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java index b20f1c80f71b..9a93f68fd374 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java @@ -457,7 +457,7 @@ private int writePrimaryClassUnit(DebugContext context, ClassEntry classEntry, b /* Only write stmt_list if the entry actually has line number info. */ if (abbrevCode == DwarfDebugInfo.DW_ABBREV_CODE_class_unit1) { log(context, " [0x%08x] stmt_list 0x%08x", pos, lineIndex); - pos = writeAttrData4(lineIndex, buffer, pos); + pos = writeAttrSecOffset(lineIndex, buffer, pos); } /* Now write the child DIEs starting with the layout and pointer type. */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java index ce45876549e2..be41d243acfa 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java @@ -206,7 +206,7 @@ protected int putRelocatableCodeOffset(long l, byte[] buffer, int p) { /* * Mark address so it is relocated relative to the start of the text segment. */ - markRelocationSite(pos, ObjectFile.RelocationKind.DIRECT_8, DwarfDebugInfo.TEXT_SECTION_NAME, false, Long.valueOf(l)); + markRelocationSite(pos, ObjectFile.RelocationKind.DIRECT_8, DwarfDebugInfo.TEXT_SECTION_NAME, l); pos = putLong(0, buffer, pos); return pos; } @@ -216,7 +216,7 @@ protected int putRelocatableHeapOffset(long l, byte[] buffer, int p) { /* * Mark address so it is relocated relative to the start of the heap. */ - markRelocationSite(pos, ObjectFile.RelocationKind.DIRECT_8, DwarfDebugInfo.HEAP_BEGIN_NAME, false, Long.valueOf(l)); + markRelocationSite(pos, ObjectFile.RelocationKind.DIRECT_8, DwarfDebugInfo.HEAP_BEGIN_NAME, l); pos = putLong(0, buffer, pos); return pos; } @@ -340,6 +340,10 @@ protected int writeAttrData4(int value, byte[] buffer, int pos) { } } + protected int writeAttrSecOffset(int value, byte[] buffer, int pos) { + return writeAttrData4(value, buffer, pos); + } + protected int writeAttrData2(short value, byte[] buffer, int pos) { if (buffer == null) { return pos + putShort(value, scratch, 0); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachOObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachOObjectFile.java index 413614d77c74..f453c86bbdec 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachOObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachOObjectFile.java @@ -429,7 +429,7 @@ public MachORelocationElement getRelocationElement() { return relocs; } - public MachORelocationElement getOrCreateRelocationElement(@SuppressWarnings("unused") boolean useImplicitAddend) { + public MachORelocationElement getOrCreateRelocationElement() { if (relocs == null) { final Segment64Command containingSegment = getOrCreateSegment(getUnnamedSegmentName(), null, false, false); relocs = new MachORelocationElement(containingSegment); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachORegularSection.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachORegularSection.java index 791c4e0f5f55..8ec4fcde87fe 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachORegularSection.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachORegularSection.java @@ -50,8 +50,8 @@ public byte[] getContent() { } @Override - public void markRelocationSite(int offset, RelocationKind k, String symbolName, boolean useImplicitAddend, Long explicitAddend) { - markRelocationSite(offset, ByteBuffer.wrap(getContent()).order(getOwner().getByteOrder()), k, symbolName, useImplicitAddend, explicitAddend); + public void markRelocationSite(int offset, RelocationKind k, String symbolName, long addend) { + markRelocationSite(offset, ByteBuffer.wrap(getContent()).order(getOwner().getByteOrder()), k, symbolName, addend); } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachORelocationElement.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachORelocationElement.java index 12328ce998c7..1c454c06e53e 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachORelocationElement.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachORelocationElement.java @@ -50,14 +50,14 @@ class MachORelocationElement extends MachOObjectFile.LinkEditElement { * within the section. */ - private static int compareSectionThenOffset(RelocationInfo p, RelocationInfo q) { + private static int compareSectionThenOffset(MachORelocationInfo p, MachORelocationInfo q) { if (!p.getRelocatedSection().equals(q.getRelocatedSection())) { return p.getRelocatedSection().hashCode() - q.getRelocatedSection().hashCode(); } return Math.toIntExact(p.getOffset() - q.getOffset()); } - private Map infos = new TreeMap<>(MachORelocationElement::compareSectionThenOffset); + private Map infos = new TreeMap<>(MachORelocationElement::compareSectionThenOffset); private Set relocatedSections = new HashSet<>(); MachORelocationElement(Segment64Command segment) { @@ -66,7 +66,7 @@ private static int compareSectionThenOffset(RelocationInfo p, RelocationInfo q) segment.getOwner().relocs = this; } - public void add(RelocationInfo rec) { + public void add(MachORelocationInfo rec) { if (infos.putIfAbsent(rec, rec) == null) { relocatedSections.add(rec.getRelocatedSection()); } @@ -79,7 +79,7 @@ public boolean relocatesSegment(Segment64Command seg) { @Override public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { OutputAssembler out = AssemblyBuffer.createOutputAssembler(getOwner().getByteOrder()); - for (RelocationInfo rec : infos.keySet()) { + for (MachORelocationInfo rec : infos.keySet()) { rec.write(out, alreadyDecided); } assert getOrDecideSize(alreadyDecided, -1) == out.pos(); @@ -98,7 +98,7 @@ public Iterable getDependencies(Map public int startIndexFor(MachOSection s) { int i = 0; - for (RelocationInfo info : infos.keySet()) { + for (MachORelocationInfo info : infos.keySet()) { if (info.getRelocatedSection() == s) { return i; } @@ -108,7 +108,7 @@ public int startIndexFor(MachOSection s) { } public int encodedEntrySize() { - return RelocationInfo.getEncodedSize(); + return MachORelocationInfo.getEncodedSize(); } public int countFor(MachOSection s) { @@ -116,50 +116,60 @@ public int countFor(MachOSection s) { } } +/** + * These are defined as an enum in + * https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/EXTERNAL_HEADERS/mach-o/x86_64/reloc.h#L173 + * which we reproduce. Of course, take care to preserve the order! + * + * For examples of how these symbols are used, see the linked file above and + * https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/EXTERNAL_HEADERS/mach-o/reloc.h. + */ enum X86_64Reloc { - /* - * These are defined as an enum in /usr/include/mach-o/x86-64/reloc.h, which we reproduce. Of - * course, take care to preserve the order! - */ - UNSIGNED, - SIGNED, - BRANCH, - GOT_LOAD, - GOT, - SUBTRACTOR, - SIGNED_1, - SIGNED_2, - SIGNED_4, - TLV; + UNSIGNED, // for absolute addresses + SIGNED, // for signed 32-bit displacement + BRANCH, // a CALL/JMP instruction with 32-bit displacement + GOT_LOAD, // a MOVQ load of a GOT entry + GOT, // other GOT references + SUBTRACTOR, // must be followed by a X86_64_RELOC_UNSIGNED + SIGNED_1, // for signed 32-bit displacement with a -1 addend + SIGNED_2, // for signed 32-bit displacement with a -2 addend + SIGNED_4, // for signed 32-bit displacement with a -4 addend + TLV; // for thread local variables public int getValue() { return ordinal(); } } +/** + * These are defined as an enum in + * https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/EXTERNAL_HEADERS/mach-o/arm64/reloc.h#L26, + * which we reproduce. Of course, take care to preserve the order! + * + * For examples of how these symbols are used, see + * https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/EXTERNAL_HEADERS/mach-o/arm/reloc.h + * (for AArch32 information, but does provide some insight) and + * https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/EXTERNAL_HEADERS/mach-o/reloc.h. + */ enum ARM64Reloc { - /* - * These are defined as an enum in /usr/include/mach-o/arm64/reloc.h, which we reproduce. Of - * course, take care to preserve the order! - */ - UNSIGNED, - SUBTRACTOR, - BRANCH26, - PAGE21, - PAGEOFF12, - GOT_LOAD_PAGE21, - GOT_LOAD_PAGEOFF12, - POINTER_TO_GOT, - TLVP_LOAD_PAGE21, - TLVP_LOAD_PAGEOFF12, - ADDEND; + UNSIGNED, // for pointers + SUBTRACTOR, // must be followed by a ARM64_RELOC_UNSIGNED + BRANCH26, // a B/BL instruction with 26-bit displacement + PAGE21, // pc-rel distance to page of target + PAGEOFF12, // offset within page, scaled by r_length + GOT_LOAD_PAGE21, // pc-rel distance to page of GOT slot + GOT_LOAD_PAGEOFF12, // offset within page of GOT slot, scaled by r_length + POINTER_TO_GOT, // for pointers to GOT slots + TLVP_LOAD_PAGE21, // pc-rel distance to page of TLVP slot + TLVP_LOAD_PAGEOFF12, // offset within page of TLVP slot, scaled by r_length + ADDEND; // must be followed by PAGE21 or PAGEOFF12 public int getValue() { return ordinal(); } } -final class RelocationInfo implements RelocationRecord, RelocationMethod { +final class MachORelocationInfo implements RelocationRecord, RelocationMethod { private final MachORelocationElement containingElement; private final MachOSection relocatedSection; @@ -179,7 +189,7 @@ final class RelocationInfo implements RelocationRecord, RelocationMethod { * @param kind the kind of relocation to perform at the relocation site * @param symbolName the symbol against which to relocate */ - RelocationInfo(MachORelocationElement containingElement, MachOSection relocatedSection, int offset, int requestedLength, RelocationKind kind, String symbolName, boolean asLocalReloc) { + MachORelocationInfo(MachORelocationElement containingElement, MachOSection relocatedSection, int offset, int requestedLength, RelocationKind kind, String symbolName, boolean asLocalReloc) { this.containingElement = containingElement; this.relocatedSection = relocatedSection; this.sectionOffset = offset; // gets turned into a vaddr on write-out @@ -261,16 +271,6 @@ public Symbol getReferencedSymbol() { return sym; } - @Override - public boolean canUseExplicitAddend() { - return false; - } - - @Override - public boolean canUseImplicitAddend() { - return true; - } - public MachOSection getRelocatedSection() { return relocatedSection; } @@ -341,7 +341,7 @@ public boolean equals(Object obj) { return true; } if (obj != null && getClass() == obj.getClass()) { - RelocationInfo other = (RelocationInfo) obj; + MachORelocationInfo other = (MachORelocationInfo) obj; return sectionOffset == other.sectionOffset && log2length == other.log2length && Objects.equals(containingElement, other.containingElement) && Objects.equals(getRelocatedSection(), other.getRelocatedSection()) && kind == other.kind && Objects.equals(sym, other.sym) && Objects.equals(targetSection, other.targetSection); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachOUserDefinedSection.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachOUserDefinedSection.java index 8a98f5e8448f..33d930f31c76 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachOUserDefinedSection.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachOUserDefinedSection.java @@ -154,35 +154,26 @@ public LayoutDecisionMap getDecisions(LayoutDecisionMap copyingIn) { } @Override - public MachORelocationElement getOrCreateRelocationElement(boolean useImplicitAddend) { - return getOwner().getOrCreateRelocationElement(useImplicitAddend); + public MachORelocationElement getOrCreateRelocationElement(long addend) { + return getOwner().getOrCreateRelocationElement(); } @Override - public void markRelocationSite(int offset, ByteBuffer bb, RelocationKind k, String symbolName, boolean useImplicitAddend, Long explicitAddend) { - MachORelocationElement el = getOrCreateRelocationElement(useImplicitAddend); + public void markRelocationSite(int offset, ByteBuffer bb, RelocationKind k, String symbolName, long addend) { + MachORelocationElement el = getOrCreateRelocationElement(addend); AssemblyBuffer sbb = new AssemblyBuffer(bb); sbb.setByteOrder(getOwner().getByteOrder()); sbb.pushSeek(offset); /* * NOTE: Mach-O does not support explicit addends, and inline addends are applied even - * during dynamic linking. So if the caller supplies an explicit addend, we turn it into an - * implicit one by updating our content. + * during dynamic linking. */ int length = ObjectFile.RelocationKind.getRelocationSize(k); - long currentInlineAddendValue = sbb.readTruncatedLong(length); - long desiredInlineAddendValue; - if (explicitAddend != null) { - /* - * This assertion is conservatively disallowing double-addend (could - * "add currentValue to explicitAddend"), because that seems more likely to be a bug - * than a feature. - */ - assert currentInlineAddendValue == 0; - desiredInlineAddendValue = explicitAddend; - } else { - desiredInlineAddendValue = currentInlineAddendValue; - } + /* + * The addend is passed as a method parameter. The initial implicit addend value within the + * instruction does not need to be read, as it is noise. + */ + long desiredInlineAddendValue = addend; /* * One more complication: for PC-relative relocation, at least on x86-64, Mach-O linkers @@ -212,7 +203,7 @@ public void markRelocationSite(int offset, ByteBuffer bb, RelocationKind k, Stri // return ByteBuffer cursor to where it was sbb.pop(); - RelocationInfo rec = new RelocationInfo(el, this, offset, length, k, symbolName, createAsLocalReloc); + MachORelocationInfo rec = new MachORelocationInfo(el, this, offset, length, k, symbolName, createAsLocalReloc); el.add(rec); } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffMachine.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffMachine.java index 5aa80dce0669..2961926c1a51 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffMachine.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffMachine.java @@ -35,12 +35,6 @@ * PECoff machine type (incomplete). Each machine type also defines its set of relocation types. */ public enum PECoffMachine/* implements Integral */ { - NONE { - @Override - Class> relocationTypes() { - return PECoffDummyRelocation.class; - } - }, X86_64 { @Override Class> relocationTypes() { @@ -69,15 +63,12 @@ public static PECoffRelocationMethod getRelocation(PECoffMachine m, RelocationKi throw new IllegalArgumentException("cannot map unknown relocation kind to an PECoff x86-64 relocation type"); } default: - case NONE: - return PECoffDummyRelocation.R_NONE; + throw new IllegalStateException("unknown PECoff machine type"); } } public static PECoffMachine from(int m) { switch (m) { - case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_UNKNOWN: - return NONE; case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64: return X86_64; default: @@ -86,9 +77,7 @@ public static PECoffMachine from(int m) { } public short toShort() { - if (this == NONE) { - return (short) IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_UNKNOWN; - } else if (this == X86_64) { + if (this == X86_64) { return (short) IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64; } else { throw new IllegalStateException("should not reach here"); @@ -104,25 +93,6 @@ public static PECoffMachine getSystemNativeValue() { } } -enum PECoffDummyRelocation implements PECoffRelocationMethod { - R_NONE; - - @Override - public boolean canUseExplicitAddend() { - return true; - } - - @Override - public boolean canUseImplicitAddend() { - return true; - } - - @Override - public long toLong() { - return ordinal(); - } -} - /** * @formatter:off * @@ -176,17 +146,4 @@ public long toLong() { return IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32; } }; - - /* - * x86-64 relocs always use explicit addends. - */ - @Override - public boolean canUseExplicitAddend() { - return true; - } - - @Override - public boolean canUseImplicitAddend() { - return false; - } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java index 138ad8457e33..cc977d3f54bb 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java @@ -662,11 +662,11 @@ public PECoffMachine getMachine() { return machine; } - public PECoffRelocationTable getOrCreateRelocSection(PECoffSymtab syms, boolean withExplicitAddends) { + public PECoffRelocationTable getOrCreateRelocSection(PECoffSymtab syms) { Element el = elementForName(".reloctab"); PECoffRelocationTable rs; if (el == null) { - rs = new PECoffRelocationTable(this, ".reloctab", syms, withExplicitAddends); + rs = new PECoffRelocationTable(this, ".reloctab", syms); } else if (el instanceof PECoffRelocationTable) { rs = (PECoffRelocationTable) el; } else { @@ -719,8 +719,8 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { // layout constraints included in the layout decision set and causes // an NPE during reloc section write. so we need to create the relevant // reloc sections here in advance - cvSymbolSectionImpl.getOrCreateRelocationElement(false); - cvTypeSectionImpl.getOrCreateRelocationElement(false); + cvSymbolSectionImpl.getOrCreateRelocationElement(0); + cvTypeSectionImpl.getOrCreateRelocationElement(0); // ok now we can populate the implementations cvDebugInfo.installDebugInfo(debugInfoProvider); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffProgbitsSection.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffProgbitsSection.java index 5bb4740dbeb7..e3f7dccae6f6 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffProgbitsSection.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffProgbitsSection.java @@ -31,8 +31,8 @@ import com.oracle.objectfile.BasicProgbitsSectionImpl; import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.ObjectFile.ProgbitsSectionImpl; -import com.oracle.objectfile.pecoff.PECoffObjectFile.PECoffSectionFlag; import com.oracle.objectfile.io.InputDisassembler; +import com.oracle.objectfile.pecoff.PECoffObjectFile.PECoffSectionFlag; public class PECoffProgbitsSection extends PECoffUserDefinedSection implements ProgbitsSectionImpl { @@ -69,7 +69,7 @@ public void setContent(byte[] c) { } @Override - public void markRelocationSite(int offset, ObjectFile.RelocationKind k, String symbolName, boolean useImplicitAddend, Long explicitAddend) { - markRelocationSite(offset, ByteBuffer.wrap(getContent()).order(getOwner().getByteOrder()), k, symbolName, useImplicitAddend, explicitAddend); + public void markRelocationSite(int offset, ObjectFile.RelocationKind k, String symbolName, long addend) { + markRelocationSite(offset, ByteBuffer.wrap(getContent()).order(getOwner().getByteOrder()), k, symbolName, addend); } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffRelocationTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffRelocationTable.java index f9cdd31e701d..163fe5ebdf38 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffRelocationTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffRelocationTable.java @@ -55,6 +55,7 @@ public ElementImpl getImpl() { } interface PECoffRelocationMethod extends RelocationMethod { + long toLong(); } @@ -101,19 +102,17 @@ public int hashCode() { } } - private final boolean withExplicitAddends; private final PECoffSymtab syms; private PECoffObjectFile owner = null; - PECoffRelocationTable(PECoffObjectFile owner, String name, PECoffSymtab syms, boolean withExplicitAddends) { + PECoffRelocationTable(PECoffObjectFile owner, String name, PECoffSymtab syms) { owner.super(name, 4); this.owner = owner; - this.withExplicitAddends = withExplicitAddends; this.syms = syms; } - public Entry addEntry(PECoffSection s, long offset, PECoffRelocationMethod t, PECoffSymtab.Entry sym, Long explicitAddend) { + void addEntry(PECoffSection s, long offset, PECoffRelocationMethod t, PECoffSymtab.Entry sym, long addend) { Map entries = (Map) s.getRelocEntries(); if (entries == null) { @@ -121,23 +120,7 @@ public Entry addEntry(PECoffSection s, long offset, PECoffRelocationMethod t, PE s.setRelocEntries(entries); } - if (explicitAddend != null) { - if (!t.canUseExplicitAddend()) { - throw new IllegalArgumentException("cannot use relocation method " + t + " with explicit addends"); - } - if (!withExplicitAddends) { - throw new IllegalStateException("cannot create relocation with addend in .rel section"); - } - } else { - if (!t.canUseImplicitAddend()) { - throw new IllegalArgumentException("cannot use relocation method " + t + " with implicit addends"); - } - if (withExplicitAddends) { - throw new IllegalStateException("cannot create relocation without addend in .rela section"); - } - } - long addend = (explicitAddend != null) ? explicitAddend : 0L; - return entries.computeIfAbsent(new Entry(s, offset, t, sym, addend), Function.identity()); + entries.computeIfAbsent(new Entry(s, offset, t, sym, addend), Function.identity()); } // Returns count of relocation entries for section diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffUserDefinedSection.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffUserDefinedSection.java index 7ffcc1d003e1..4d34aa1ee8a9 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffUserDefinedSection.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffUserDefinedSection.java @@ -49,7 +49,6 @@ public class PECoffUserDefinedSection extends PECoffSection implements ObjectFile.RelocatableSectionImpl { private PECoffRelocationTable rel; // the section holding our relocations without addends - private PECoffRelocationTable rela; // the section holding our relocations with addends protected ElementImpl impl; @@ -119,33 +118,23 @@ public LayoutDecisionMap getDecisions(LayoutDecisionMap copyingIn) { } @Override - public Element getOrCreateRelocationElement(boolean useImplicitAddend) { + public Element getOrCreateRelocationElement(long addend) { PECoffSymtab syms = (PECoffSymtab) getOwner().elementForName(".symtab"); if (syms == null) { throw new IllegalStateException("cannot create a relocation section without corresponding symtab"); } - boolean withExplicitAddends = !useImplicitAddend; - PECoffRelocationTable rs = withExplicitAddends ? rela : rel; - if (rs == null) { - // we have to create the section if it doesn't exist - rs = getOwner().getOrCreateRelocSection(syms, withExplicitAddends); - assert rs != null; - if (withExplicitAddends) { - rela = rs; - } else { - rel = rs; - } + + if (rel == null) { + rel = getOwner().getOrCreateRelocSection(syms); + assert rel != null; } - return rs; + return rel; } @Override - public void markRelocationSite(int offset, ByteBuffer bb, ObjectFile.RelocationKind k, String symbolName, boolean useImplicitAddend, Long explicitAddend) { - if (useImplicitAddend != (explicitAddend == null)) { - throw new IllegalArgumentException("must have either an explicit or implicit addend"); - } + public void markRelocationSite(int offset, ByteBuffer bb, ObjectFile.RelocationKind k, String symbolName, long addend) { PECoffSymtab syms = (PECoffSymtab) getOwner().elementForName(".symtab"); - PECoffRelocationTable rs = (PECoffRelocationTable) getOrCreateRelocationElement(useImplicitAddend); + PECoffRelocationTable rs = (PECoffRelocationTable) getOrCreateRelocationElement(addend); assert symbolName != null; PECoffSymtab.Entry ent = syms.getSymbol(symbolName); if (ent == null) { @@ -158,23 +147,14 @@ public void markRelocationSite(int offset, ByteBuffer bb, ObjectFile.RelocationK sbb.pushSeek(offset); /* * NOTE: Windows does not support explicit addends, and inline addends are applied even - * during dynamic linking. So if the caller supplies an explicit addend, we turn it into an - * implicit one by updating our content. + * during dynamic linking. */ int length = ObjectFile.RelocationKind.getRelocationSize(k); - long currentInlineAddendValue = sbb.readTruncatedLong(length); - long desiredInlineAddendValue; - if (explicitAddend != null) { - /* - * This assertion is conservatively disallowing double-addend (could - * "add currentValue to explicitAddend"), because that seems more likely to be a bug - * than a feature. - */ - assert currentInlineAddendValue == 0; - desiredInlineAddendValue = explicitAddend; - } else { - desiredInlineAddendValue = currentInlineAddendValue; - } + /* + * The addend is passed as a method parameter. The initial implicit addend value within the + * instruction does not need to be read, as it is noise. + */ + long desiredInlineAddendValue = addend; /* * One more complication: for PC-relative relocation, at least on x86-64, Coff linkers @@ -196,7 +176,7 @@ public void markRelocationSite(int offset, ByteBuffer bb, ObjectFile.RelocationK // return ByteBuffer cursor to where it was sbb.pop(); - rs.addEntry(this, offset, PECoffMachine.getRelocation(getOwner().getMachine(), k), ent, explicitAddend); + rs.addEntry(this, offset, PECoffMachine.getRelocation(getOwner().getMachine(), k), ent, addend); } /** diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java index 090f30fe4acb..46dc4f9072b7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java @@ -92,9 +92,9 @@ private int computeHeader(byte[] buffer, int initialPos) { int pos = initialPos; /* Emit addr:section relocation records. */ - cvDebugInfo.getCVSymbolSection().markRelocationSite(pos, ObjectFile.RelocationKind.SECREL_4, symbolName, false, 1L); + cvDebugInfo.getCVSymbolSection().markRelocationSite(pos, ObjectFile.RelocationKind.SECREL_4, symbolName, 1L); pos = CVUtil.putInt(0, buffer, pos); - cvDebugInfo.getCVSymbolSection().markRelocationSite(pos, ObjectFile.RelocationKind.SECTION_2, symbolName, false, 1L); + cvDebugInfo.getCVSymbolSection().markRelocationSite(pos, ObjectFile.RelocationKind.SECTION_2, symbolName, 1L); pos = CVUtil.putShort((short) 0, buffer, pos); /* Emit flags. */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java index ddb43d1039c7..4a2cf1320132 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java @@ -297,11 +297,11 @@ protected int computeContents(byte[] buffer, int initialPos) { pos = CVUtil.putInt(debugEnd, buffer, pos); pos = CVUtil.putInt(typeIndex, buffer, pos); if (buffer != null) { - cvDebugInfo.getCVSymbolSection().markRelocationSite(pos, ObjectFile.RelocationKind.SECREL_4, externalName, false, 1L); + cvDebugInfo.getCVSymbolSection().markRelocationSite(pos, ObjectFile.RelocationKind.SECREL_4, externalName, 1L); } pos = CVUtil.putInt(0, buffer, pos); if (buffer != null) { - cvDebugInfo.getCVSymbolSection().markRelocationSite(pos, ObjectFile.RelocationKind.SECTION_2, externalName, false, 1L); + cvDebugInfo.getCVSymbolSection().markRelocationSite(pos, ObjectFile.RelocationKind.SECTION_2, externalName, 1L); } pos = CVUtil.putShort((short) 0, buffer, pos); pos = CVUtil.putByte(flags, buffer, pos); diff --git a/substratevm/src/com.oracle.svm.common/src/com/oracle/svm/common/option/CommonOptionParser.java b/substratevm/src/com.oracle.svm.common/src/com/oracle/svm/common/option/CommonOptionParser.java new file mode 100644 index 000000000000..896a9f3aedf4 --- /dev/null +++ b/substratevm/src/com.oracle.svm.common/src/com/oracle/svm/common/option/CommonOptionParser.java @@ -0,0 +1,522 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2021, Alibaba Group Holding Limited. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.svm.common.option; + +// Checkstyle: allow reflection + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Predicate; + +import org.graalvm.collections.EconomicMap; +import org.graalvm.compiler.options.OptionDescriptor; +import org.graalvm.compiler.options.OptionDescriptors; +import org.graalvm.compiler.options.OptionKey; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionsParser; + +import com.oracle.svm.util.ClassUtil; +import com.oracle.svm.util.StringUtil; + +public class CommonOptionParser { + public static final String HOSTED_OPTION_PREFIX = "-H:"; + public static final String RUNTIME_OPTION_PREFIX = "-R:"; + + public static final int PRINT_OPTION_INDENTATION = 2; + public static final int PRINT_OPTION_WIDTH = 45; + public static final int PRINT_OPTION_WRAP_WIDTH = 120; + + /** + * The result of {@link CommonOptionParser#parseOption}. + */ + public static final class OptionParseResult { + private final EnumSet printFlags; + private final Set optionNameFilter; + private final String error; + private final OptionKey optionKey; + private static final String EXTRA_HELP_OPTIONS_WILDCARD = "*"; + + OptionParseResult(EnumSet printFlags, String error, Set optionNameFilter, OptionKey optionKey) { + this.printFlags = printFlags; + this.error = error; + this.optionNameFilter = optionNameFilter; + this.optionKey = optionKey; + } + + private OptionParseResult(EnumSet printFlags, String error, OptionKey optionKey) { + this(printFlags, error, new HashSet<>(), optionKey); + } + + static OptionParseResult error(String message) { + return new OptionParseResult(EnumSet.noneOf(OptionType.class), message, null); + } + + static OptionParseResult correct(OptionKey optionKey) { + return new OptionParseResult(EnumSet.noneOf(OptionType.class), null, optionKey); + } + + static OptionParseResult printFlags(EnumSet selectedOptionTypes) { + return new OptionParseResult(selectedOptionTypes, null, null); + } + + static OptionParseResult printFlagsWithExtraHelp(Set optionNameFilter) { + Set optionNames = optionNameFilter; + if (optionNames.contains(EXTRA_HELP_OPTIONS_WILDCARD)) { + optionNames = new HashSet<>(); + optionNames.add(EXTRA_HELP_OPTIONS_WILDCARD); + } + return new OptionParseResult(EnumSet.noneOf(OptionType.class), null, optionNames, null); + } + + public boolean printFlags() { + return !printFlags.isEmpty(); + } + + public boolean printFlagsWithExtraHelp() { + return !optionNameFilter.isEmpty(); + } + + public boolean isValid() { + boolean result = optionKey != null; + assert result == (printFlags.isEmpty() && optionNameFilter.isEmpty() && error == null); + return result; + } + + public String getError() { + return error; + } + + public OptionKey getOptionKey() { + return optionKey; + } + + public boolean matchesFlags(OptionDescriptor d, boolean svmOption) { + if (!printFlags.isEmpty()) { + boolean showAll = printFlags.equals(EnumSet.allOf(OptionType.class)); + return showAll || svmOption && printFlags.contains(d.getOptionType()); + } + if (!optionNameFilter.isEmpty()) { + if (optionNameFilter.contains(EXTRA_HELP_OPTIONS_WILDCARD) && !d.getExtraHelp().isEmpty()) { + return true; + } + return optionNameFilter.contains(d.getName()); + } + return false; + } + } + + /** + * Constants denoting supported boolean option formats. + */ + public enum BooleanOptionFormat { + NAME_VALUE("="), + PLUS_MINUS("+/-"); + + BooleanOptionFormat(String help) { + this.help = help; + } + + private final String help; + + @Override + public String toString() { + return help; + } + } + + public static void collectOptions(ServiceLoader optionDescriptors, Consumer optionDescriptorConsumer) { + for (OptionDescriptors optionDescriptor : optionDescriptors) { + for (OptionDescriptor descriptor : optionDescriptor) { + optionDescriptorConsumer.accept(descriptor); + } + } + } + + public static OptionParseResult parseOption(EconomicMap options, Predicate> isHosted, String option, EconomicMap, Object> valuesMap, + String optionPrefix, BooleanOptionFormat booleanOptionFormat) throws UnsupportedOptionClassException { + if (option.length() == 0) { + return OptionParseResult.error("Option name must be specified"); + } + + String optionName; + Object value = null; + String valueString = null; + + char first = option.charAt(0); + int eqIndex = option.indexOf('='); + if (first == '+' || first == '-') { + if (eqIndex != -1) { + return OptionParseResult.error("Cannot mix +/- with = format: '" + optionPrefix + option + "'"); + } + optionName = option.substring(1); + if (booleanOptionFormat == BooleanOptionFormat.NAME_VALUE) { + return OptionParseResult.error("Option " + LocatableOption.from(optionName) + " must use = format, not +/- prefix"); + } + value = (first == '+'); + } else { + if (eqIndex == -1) { + optionName = option; + valueString = null; + } else { + optionName = option.substring(0, eqIndex); + valueString = option.substring(eqIndex + 1); + } + } + + LocatableOption current = LocatableOption.from(optionName); + OptionDescriptor desc = options.get(current.name); + if (desc == null && value != null) { + if (eqIndex != -1) { + optionName = option.substring(1, eqIndex); + current = LocatableOption.from(optionName); + desc = options.get(current.name); + } + } + + optionName = current.name; + + if (desc == null) { + List matches = new ArrayList<>(); + OptionsParser.collectFuzzyMatches(options.getValues(), optionName, matches); + StringBuilder msg = new StringBuilder("Could not find option ").append(current); + if (!matches.isEmpty()) { + msg.append(". Did you mean one of these:"); + for (OptionDescriptor match : matches) { + msg.append(' ').append(match.getName()); + } + } + msg.append(". Use ").append(optionPrefix).append(CommonOptions.PrintFlags.getName()).append("= to list all available options."); + return OptionParseResult.error(msg.toString()); + } + + OptionKey optionKey = desc.getOptionKey(); + boolean hostedOption = isHosted.test(optionKey); + Class optionValueType = getMultiOptionValueElementType(optionKey); + Class optionType = hostedOption && optionValueType != null ? optionValueType : desc.getOptionValueType(); + + if (value == null) { + if (optionType == Boolean.class && booleanOptionFormat == BooleanOptionFormat.PLUS_MINUS) { + return OptionParseResult.error("Boolean option " + current + " must have +/- prefix"); + } + if (valueString == null) { + return OptionParseResult.error("Missing value for option " + current); + } + try { + value = parseValue(optionType, current, valueString); + if (value instanceof OptionParseResult) { + return (OptionParseResult) value; + } + } catch (NumberFormatException ex) { + return OptionParseResult.error("Invalid value for option " + current + ": '" + valueString + "' is not a valid number"); + } + } else { + if (optionType != Boolean.class) { + return OptionParseResult.error("Non-boolean option " + current + " can not use +/- prefix. Use '" + current.name + "=' format"); + } + } + + optionKey.update(valuesMap, hostedOption ? LocatableOption.value(value, current.origin) : value); + + if (CommonOptions.PrintFlags.getName().equals(optionName)) { + String optionValue = (String) value; + EnumSet selectedOptionTypes; + if (optionValue.isEmpty()) { + selectedOptionTypes = EnumSet.allOf(OptionType.class); + } else { + selectedOptionTypes = EnumSet.noneOf(OptionType.class); + String enumString = null; + try { + String[] enumStrings = StringUtil.split(optionValue, ","); + + for (String string : enumStrings) { + enumString = string; + selectedOptionTypes.add(OptionType.valueOf(enumString)); + } + } catch (IllegalArgumentException e) { + StringBuilder sb = new StringBuilder(); + boolean firstValue = true; + for (OptionType ot : OptionType.values()) { + if (firstValue) { + firstValue = false; + } else { + sb.append(", "); + } + sb.append(ot.name()); + } + String possibleValues = sb.toString(); + return OptionParseResult.error("Invalid value for option " + current + ". '" + enumString + "' is not one of: " + possibleValues); + } + } + return OptionParseResult.printFlags(selectedOptionTypes); + } + + if (CommonOptions.PrintFlagsWithExtraHelp.getName().equals(optionName)) { + String optionValue = (String) value; + String[] optionNames = StringUtil.split(optionValue, ","); + HashSet selectedOptionNames = new HashSet<>(Arrays.asList(optionNames)); + return OptionParseResult.printFlagsWithExtraHelp(selectedOptionNames); + } + return OptionParseResult.correct(optionKey); + } + + @SuppressWarnings("unchecked") + static Object parseValue(Class optionType, LocatableOption option, String valueString) throws NumberFormatException, UnsupportedOptionClassException { + Object value; + if (optionType == Integer.class) { + long longValue = parseLong(valueString); + if ((int) longValue != longValue) { + return OptionParseResult.error("Wrong value for option " + option + ": '" + valueString + "' is not a valid number"); + } + value = (int) longValue; + } else if (optionType == Long.class) { + value = parseLong(valueString); + } else if (optionType == String.class) { + value = valueString; + } else if (optionType == Double.class) { + value = parseDouble(valueString); + } else if (optionType == Boolean.class) { + if (valueString.equals("true")) { + value = true; + } else if (valueString.equals("false")) { + value = false; + } else { + return OptionParseResult.error("Boolean option " + option + " must have value 'true' or 'false'"); + } + } else if (optionType.isEnum()) { + value = Enum.valueOf(optionType.asSubclass(Enum.class), valueString); + } else { + throw new UnsupportedOptionClassException(option + " uses unsupported option value class: " + ClassUtil.getUnqualifiedName(optionType)); + } + return value; + } + + private static Class getMultiOptionValueElementType(OptionKey optionKey) { + Object defaultValue = optionKey.getDefaultValue(); + if (defaultValue instanceof MultiOptionValue) { + return ((MultiOptionValue) defaultValue).getValueType(); + } + return null; + } + + public static long parseLong(String v) { + String valueString = v.trim().toLowerCase(); + long scale = 1; + if (valueString.endsWith("k")) { + scale = 1024L; + } else if (valueString.endsWith("m")) { + scale = 1024L * 1024L; + } else if (valueString.endsWith("g")) { + scale = 1024L * 1024L * 1024L; + } else if (valueString.endsWith("t")) { + scale = 1024L * 1024L * 1024L * 1024L; + } + + if (scale != 1) { + /* Remove trailing scale character. */ + valueString = valueString.substring(0, valueString.length() - 1); + } + + return Long.parseLong(valueString) * scale; + } + + /** + * Parses the provided string to a double number, avoiding the JDK dependencies (which pull in a + * lot of classes, including the regular expression library). Only simple numbers are supported, + * without fancy exponent styles. + */ + public static double parseDouble(String v) { + String valueString = v.trim(); + + int dotPos = valueString.indexOf('.'); + if (dotPos == -1) { + return parseLong(valueString); + } + + String beforeDot = valueString.substring(0, dotPos); + String afterDot = valueString.substring(dotPos + 1); + + double sign = 1; + if (beforeDot.startsWith("-")) { + sign = -1; + beforeDot = beforeDot.substring(1); + } else if (beforeDot.startsWith("+")) { + beforeDot = beforeDot.substring(1); + } + + if (beforeDot.startsWith("-") || beforeDot.startsWith("+") || afterDot.startsWith("-") || afterDot.startsWith("+") || + (beforeDot.length() == 0 && afterDot.length() == 0)) { + throw new NumberFormatException(v); + } + + double integral = 0; + if (beforeDot.length() > 0) { + integral = Long.parseLong(beforeDot); + } + + double fraction = 0; + if (afterDot.length() > 0) { + fraction = Long.parseLong(afterDot) * Math.pow(10, -afterDot.length()); + } + + return sign * (integral + fraction); + } + + private static String spaces(int length) { + return new String(new char[length]).replace('\0', ' '); + } + + private static String wrap(String s, int width) { + StringBuilder sb = new StringBuilder(s); + int cursor = 0; + while (cursor + width < sb.length()) { + int i = sb.lastIndexOf(" ", cursor + width); + if (i == -1 || i < cursor) { + i = sb.indexOf(" ", cursor + width); + } + if (i != -1) { + sb.replace(i, i + 1, System.lineSeparator()); + cursor = i; + } else { + break; + } + } + return sb.toString(); + } + + private static void printOption(PrintStream out, String option, String description, int wrap) { + printOption(out::println, option, description, PRINT_OPTION_INDENTATION, PRINT_OPTION_WIDTH, wrap); + } + + public static void printOption(Consumer println, String option, String description, int indentation, int optionWidth, int wrapWidth) { + String indent = spaces(indentation); + String desc = description != null ? description : ""; + desc = wrapWidth > 0 ? wrap(desc, wrapWidth) : desc; + String nl = System.lineSeparator(); + String[] descLines = StringUtil.split(desc, nl); + if (option.length() >= optionWidth && description != null) { + println.accept(indent + option + nl + indent + spaces(optionWidth) + descLines[0]); + } else { + println.accept(indent + option + spaces(optionWidth - option.length()) + descLines[0]); + } + for (int i = 1; i < descLines.length; i++) { + println.accept(indent + spaces(optionWidth) + descLines[i]); + } + } + + public static void printFlags(Predicate filter, EconomicMap options, String prefix, PrintStream out, boolean verbose) { + List sortedDescriptors = new ArrayList<>(); + for (OptionDescriptor option : options.getValues()) { + if (filter.test(option)) { + sortedDescriptors.add(option); + } + } + sortedDescriptors.sort(Comparator.comparing(OptionDescriptor::getName)); + + for (OptionDescriptor descriptor : sortedDescriptors) { + String helpMsg = verbose && !descriptor.getExtraHelp().isEmpty() ? "" : descriptor.getHelp(); + int helpLen = helpMsg.length(); + if (helpLen > 0 && helpMsg.charAt(helpLen - 1) != '.') { + helpMsg += '.'; + } + boolean stringifiedArrayValue = false; + Object defaultValue = descriptor.getOptionKey().getDefaultValue(); + if (defaultValue != null && defaultValue.getClass().isArray()) { + Object[] defaultValues = (Object[]) defaultValue; + if (defaultValues.length == 1) { + defaultValue = defaultValues[0]; + } else { + List stringList = new ArrayList<>(); + String optionPrefix = prefix + descriptor.getName() + "="; + for (Object rawValue : defaultValues) { + String value; + if (rawValue instanceof String) { + value = '"' + String.valueOf(rawValue) + '"'; + } else { + value = String.valueOf(rawValue); + } + stringList.add(optionPrefix + value); + } + if (helpLen != 0) { + helpMsg += ' '; + } + helpMsg += "Default: "; + if (stringList.isEmpty()) { + helpMsg += "None"; + } else { + helpMsg += String.join(" ", stringList); + } + stringifiedArrayValue = true; + } + } + String verboseHelp = ""; + if (verbose) { + verboseHelp = System.lineSeparator() + descriptor.getHelp() + System.lineSeparator() + String.join(System.lineSeparator(), descriptor.getExtraHelp()); + } else if (!descriptor.getExtraHelp().isEmpty()) { + verboseHelp = " [Extra help available]"; + } + int wrapWidth = verbose ? 0 : PRINT_OPTION_WRAP_WIDTH; + if (descriptor.getOptionValueType() == Boolean.class) { + Boolean val = (Boolean) defaultValue; + if (helpLen != 0) { + helpMsg += ' '; + } + if (val != null) { + if (val) { + helpMsg += "Default: + (enabled)."; + } else { + helpMsg += "Default: - (disabled)."; + } + } + printOption(out, prefix + "\u00b1" + descriptor.getName(), helpMsg + verboseHelp, wrapWidth); + } else { + if (defaultValue == null) { + if (helpLen != 0) { + helpMsg += ' '; + } + helpMsg += "Default: None"; + } + helpMsg += verboseHelp; + if (stringifiedArrayValue || defaultValue == null) { + printOption(out, prefix + descriptor.getName() + "=...", helpMsg, wrapWidth); + } else { + if (defaultValue instanceof String) { + defaultValue = '"' + String.valueOf(defaultValue) + '"'; + } + printOption(out, prefix + descriptor.getName() + "=" + defaultValue, helpMsg, wrapWidth); + } + } + } + } +} diff --git a/substratevm/src/com.oracle.svm.common/src/com/oracle/svm/common/option/CommonOptions.java b/substratevm/src/com.oracle.svm.common/src/com/oracle/svm/common/option/CommonOptions.java new file mode 100644 index 000000000000..6b2f9e88b5d6 --- /dev/null +++ b/substratevm/src/com.oracle.svm.common/src/com/oracle/svm/common/option/CommonOptions.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2021, Alibaba Group Holding Limited. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.svm.common.option; + +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionKey; + +public class CommonOptions { + + @Option(help = "Show available options based on comma-separated option-types (allowed categories: User, Expert, Debug).")// + public static final OptionKey PrintFlags = new OptionKey<>(null); + + @Option(help = "Print extra help, if available, based on comma-separated option names. Pass * to show all options that contain extra help.")// + public static final OptionKey PrintFlagsWithExtraHelp = new OptionKey<>(null); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/LocatableOption.java b/substratevm/src/com.oracle.svm.common/src/com/oracle/svm/common/option/LocatableOption.java similarity index 96% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/LocatableOption.java rename to substratevm/src/com.oracle.svm.common/src/com/oracle/svm/common/option/LocatableOption.java index d675521de43d..62927c9a3a31 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/LocatableOption.java +++ b/substratevm/src/com.oracle.svm.common/src/com/oracle/svm/common/option/LocatableOption.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2021, Alibaba Group Holding Limited. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +23,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.option; +package com.oracle.svm.common.option; public final class LocatableOption { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/MultiOptionValue.java b/substratevm/src/com.oracle.svm.common/src/com/oracle/svm/common/option/MultiOptionValue.java similarity index 80% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/MultiOptionValue.java rename to substratevm/src/com.oracle.svm.common/src/com/oracle/svm/common/option/MultiOptionValue.java index ad6207f9036e..2c44d2ce4997 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/MultiOptionValue.java +++ b/substratevm/src/com.oracle.svm.common/src/com/oracle/svm/common/option/MultiOptionValue.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2021, Alibaba Group Holding Limited. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,19 +23,16 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.option; +package com.oracle.svm.common.option; import java.util.List; -interface MultiOptionValue { +public interface MultiOptionValue { Class getValueType(); /** - * @return a list of option values, one for each place where the option is used - * @implSpec Note that it DOES NOT perform any splitting of string values based on a delimiter. - * If you want to perform this split, use a utility - * {@link OptionUtils#flatten(String, LocatableMultiOptionValue.Strings)} + * @return a list of option values, one for each place where the option is used. */ List values(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK14OrLater.java b/substratevm/src/com.oracle.svm.common/src/com/oracle/svm/common/option/OptionParsingException.java similarity index 75% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK14OrLater.java rename to substratevm/src/com.oracle.svm.common/src/com/oracle/svm/common/option/OptionParsingException.java index 57e1645fbbd6..87e2d281bdd8 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK14OrLater.java +++ b/substratevm/src/com.oracle.svm.common/src/com/oracle/svm/common/option/OptionParsingException.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2021, Alibaba Group Holding Limited. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,15 +23,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk; -import java.util.function.BooleanSupplier; +package com.oracle.svm.common.option; -import org.graalvm.compiler.serviceprovider.JavaVersionUtil; +public class OptionParsingException extends Exception { + private static final long serialVersionUID = 1413275434484971842L; -public class JDK14OrLater implements BooleanSupplier { - @Override - public boolean getAsBoolean() { - return JavaVersionUtil.JAVA_SPEC >= 14; + public OptionParsingException(Exception e) { + super(e); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK14OrEarlier.java b/substratevm/src/com.oracle.svm.common/src/com/oracle/svm/common/option/UnsupportedOptionClassException.java similarity index 74% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK14OrEarlier.java rename to substratevm/src/com.oracle.svm.common/src/com/oracle/svm/common/option/UnsupportedOptionClassException.java index 1a1941e754c4..c92195df9443 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK14OrEarlier.java +++ b/substratevm/src/com.oracle.svm.common/src/com/oracle/svm/common/option/UnsupportedOptionClassException.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2021, Alibaba Group Holding Limited. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,15 +23,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk; -import java.util.function.BooleanSupplier; +package com.oracle.svm.common.option; -import org.graalvm.compiler.serviceprovider.JavaVersionUtil; +public class UnsupportedOptionClassException extends Exception { + private static final long serialVersionUID = -3105370072461246590L; -public class JDK14OrEarlier implements BooleanSupplier { - @Override - public boolean getAsBoolean() { - return JavaVersionUtil.JAVA_SPEC <= 14; + public UnsupportedOptionClassException(String msg) { + super(msg); } } diff --git a/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/OmitPreviousConfigTests.java b/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/OmitPreviousConfigTests.java index 508600f2cb2d..16ddb241dbd3 100644 --- a/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/OmitPreviousConfigTests.java +++ b/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/OmitPreviousConfigTests.java @@ -154,21 +154,21 @@ private static void doTestExpectedMissingTypes(TypeConfiguration typeConfig) { private static void doTestTypeFlags(TypeConfiguration typeConfig) { ConfigurationType flagTestHasDeclaredType = getConfigTypeOrFail(typeConfig, "FlagTestC"); - Assert.assertTrue(flagTestHasDeclaredType.haveAllDeclaredClasses() || flagTestHasDeclaredType.haveAllDeclaredFields() || - flagTestHasDeclaredType.getAllDeclaredConstructors() == ConfigurationMemberAccessibility.ACCESSED); + Assert.assertTrue(ConfigurationType.TestBackdoor.haveAllDeclaredClasses(flagTestHasDeclaredType) || ConfigurationType.TestBackdoor.haveAllDeclaredFields(flagTestHasDeclaredType) || + ConfigurationType.TestBackdoor.getAllDeclaredConstructors(flagTestHasDeclaredType) == ConfigurationMemberAccessibility.ACCESSED); ConfigurationType flagTestHasPublicType = getConfigTypeOrFail(typeConfig, "FlagTestD"); - Assert.assertTrue(flagTestHasPublicType.haveAllPublicClasses() || flagTestHasPublicType.haveAllPublicFields() || - flagTestHasPublicType.getAllPublicConstructors() == ConfigurationMemberAccessibility.ACCESSED); + Assert.assertTrue(ConfigurationType.TestBackdoor.haveAllPublicClasses(flagTestHasPublicType) || ConfigurationType.TestBackdoor.haveAllPublicFields(flagTestHasPublicType) || + ConfigurationType.TestBackdoor.getAllPublicConstructors(flagTestHasPublicType) == ConfigurationMemberAccessibility.ACCESSED); } private static void doTestFields(TypeConfiguration typeConfig) { ConfigurationType fieldTestType = getConfigTypeOrFail(typeConfig, "MethodAndFieldTest"); - Assert.assertNull(fieldTestType.getFieldInfoIfPresent("SimpleField")); - Assert.assertNull(fieldTestType.getFieldInfoIfPresent("AllowWriteField")); + Assert.assertNull(ConfigurationType.TestBackdoor.getFieldInfoIfPresent(fieldTestType, "SimpleField")); + Assert.assertNull(ConfigurationType.TestBackdoor.getFieldInfoIfPresent(fieldTestType, "AllowWriteField")); - FieldInfo newField = fieldTestType.getFieldInfoIfPresent("NewField"); + FieldInfo newField = ConfigurationType.TestBackdoor.getFieldInfoIfPresent(fieldTestType, "NewField"); Assert.assertFalse(newField.isFinalButWritable()); FieldInfo newWritableField = getFieldInfoOrFail(fieldTestType, "NewAllowWriteField"); @@ -181,8 +181,8 @@ private static void doTestFields(TypeConfiguration typeConfig) { private static void doTestMethods(TypeConfiguration typeConfig) { ConfigurationType methodTestType = getConfigTypeOrFail(typeConfig, "MethodAndFieldTest"); - Assert.assertNull(methodTestType.getMethodKindIfPresent(new ConfigurationMethod("", "(I)V"))); - Assert.assertNotNull(methodTestType.getMethodKindIfPresent(new ConfigurationMethod("method", "()V"))); + Assert.assertNull(ConfigurationType.TestBackdoor.getMethodInfoIfPresent(methodTestType, new ConfigurationMethod("", "(I)V"))); + Assert.assertNotNull(ConfigurationType.TestBackdoor.getMethodInfoIfPresent(methodTestType, new ConfigurationMethod("method", "()V"))); } private static void doTestProxyConfig(ProxyConfiguration proxyConfig) { @@ -213,7 +213,7 @@ private static ConfigurationType getConfigTypeOrFail(TypeConfiguration typeConfi } private static FieldInfo getFieldInfoOrFail(ConfigurationType type, String field) { - FieldInfo fieldInfo = type.getFieldInfoIfPresent(field); + FieldInfo fieldInfo = ConfigurationType.TestBackdoor.getFieldInfoIfPresent(type, field); Assert.assertNotNull(fieldInfo); return fieldInfo; } @@ -242,7 +242,6 @@ class TypeMethodsWithFlagsTest { this.methodKind = methodKind; generateTestMethods(); populateConfig(); - currentConfig.removeAll(previousConfig); } void generateTestMethods() { @@ -301,20 +300,22 @@ String getTypeName() { } void doTest() { + TypeConfiguration currentConfigWithoutPrevious = TypeConfiguration.copyAndSubtract(currentConfig, previousConfig); + String name = getTypeName(); - ConfigurationType configurationType = currentConfig.get(ConfigurationCondition.alwaysTrue(), name); + ConfigurationType configurationType = currentConfigWithoutPrevious.get(ConfigurationCondition.alwaysTrue(), name); if (methodsThatMustExist.size() == 0) { Assert.assertNull("Generated configuration type " + name + " exists. Expected it to be cleared as it is empty.", configurationType); } else { Assert.assertNotNull("Generated configuration type " + name + " does not exist. Has the test code changed?", configurationType); for (Map.Entry methodEntry : methodsThatMustExist.entrySet()) { - ConfigurationMemberDeclaration kind = configurationType.getMethodKindIfPresent(methodEntry.getKey()).getMemberKind(); + ConfigurationMemberDeclaration kind = ConfigurationType.TestBackdoor.getMethodInfoIfPresent(configurationType, methodEntry.getKey()).getMemberKind(); Assert.assertNotNull("Method " + methodEntry.getKey() + " unexpectedly NOT found in the new configuration.", kind); Assert.assertEquals("Method " + methodEntry.getKey() + " contains a different kind than expected in the new configuration.", kind, methodEntry.getValue()); } for (Map.Entry methodEntry : methodsThatMustNotExist.entrySet()) { - ConfigurationMemberInfo kind = configurationType.getMethodKindIfPresent(methodEntry.getKey()); + ConfigurationMemberInfo kind = ConfigurationType.TestBackdoor.getMethodInfoIfPresent(configurationType, methodEntry.getKey()); Assert.assertNull("Method " + methodEntry.getKey() + " unexpectedly found in the new configuration.", kind); } } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java index 7d95a4c1834a..10d0186441fb 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java @@ -29,6 +29,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiFunction; import java.util.function.BiPredicate; import java.util.function.Consumer; @@ -42,7 +43,30 @@ import com.oracle.svm.configure.json.JsonPrinter; import com.oracle.svm.configure.json.JsonWriter; +/** + * Type usage information, part of a {@link TypeConfiguration}. Unlike other configuration classes + * like {@link ConfigurationMethod}, this class is not immutable and uses locking to synchronize + * changes during trace processing. Merely using {@link ConcurrentHashMap} is not sufficient because + * of relationships between fields (e.g. {@link #allDeclaredMethodsAccess} and {@link #methods}) and + * so related fields must be read and updated together. + */ public class ConfigurationType implements JsonPrintable { + static ConfigurationType copyAndSubtract(ConfigurationType type, ConfigurationType subtractType) { + if (type.equals(subtractType)) { + return null; + } + ConfigurationType copy = new ConfigurationType(type); + if (subtractType == null) { + return copy; + } + + assert type.getCondition().equals(subtractType.getCondition()); + assert type.getQualifiedJavaName().equals(subtractType.getQualifiedJavaName()); + + copy.removeAll(subtractType); + return copy.isEmpty() ? null : copy; + } + private final ConfigurationCondition condition; private final String qualifiedJavaName; @@ -65,25 +89,28 @@ public ConfigurationType(ConfigurationCondition condition, String qualifiedJavaN this.qualifiedJavaName = qualifiedJavaName; } - public ConfigurationType(ConfigurationType other) { - qualifiedJavaName = other.qualifiedJavaName; - condition = other.condition; - mergeWith(other); + private ConfigurationType(ConfigurationType other) { + // Our object is not yet published, so it is sufficient to take only the other object's lock + synchronized (other) { + qualifiedJavaName = other.qualifiedJavaName; + condition = other.condition; + mergeFrom(other); + } } - public void mergeWith(ConfigurationType other) { + private void mergeFrom(ConfigurationType other) { assert condition.equals(other.condition); assert qualifiedJavaName.equals(other.qualifiedJavaName); - mergeFlagsWith(other); - mergeFieldsWith(other); - mergeMethodsWith(other); + mergeFlagsFrom(other); + mergeFieldsFrom(other); + mergeMethodsFrom(other); } - private void mergeFlagsWith(ConfigurationType other) { + private void mergeFlagsFrom(ConfigurationType other) { setFlagsFromOther(other, (our, their) -> our || their, ConfigurationMemberAccessibility::combine); } - private void mergeFieldsWith(ConfigurationType other) { + private void mergeFieldsFrom(ConfigurationType other) { if (other.fields != null) { if (fields == null) { fields = new HashMap<>(); @@ -110,7 +137,7 @@ private void maybeRemoveFields(boolean hasAllDeclaredFields, boolean hasAllPubli } } - private void mergeMethodsWith(ConfigurationType other) { + private void mergeMethodsFrom(ConfigurationType other) { if (other.methods != null) { if (methods == null) { methods = new HashMap<>(); @@ -146,7 +173,7 @@ private void maybeRemoveMethods(ConfigurationMemberAccessibility hasAllDeclaredM } } - public void removeAll(ConfigurationType other) { + private void removeAll(ConfigurationType other) { assert condition.equals(other.condition); assert qualifiedJavaName.equals(other.qualifiedJavaName); removeFlags(other); @@ -193,7 +220,7 @@ private void setFlagsFromOther(ConfigurationType other, BiPredicate { FieldInfo fieldInfo = map.get(name); if (fieldInfo != null && !fieldInfo.isFinalButWritable()) { @@ -227,10 +255,6 @@ public void addField(String name, ConfigurationMemberDeclaration memberKind, boo : FieldInfo.get(memberKind, finalButWritable)); } - public void addMethodsWithName(String name, ConfigurationMemberDeclaration memberKind) { - addMethod(name, null, memberKind, ConfigurationMemberAccessibility.ACCESSED); - } - public void addMethodsWithName(String name, ConfigurationMemberDeclaration memberKind, ConfigurationMemberAccessibility accessKind) { addMethod(name, null, memberKind, accessKind); } @@ -239,7 +263,7 @@ public void addMethod(String name, String internalSignature, ConfigurationMember addMethod(name, internalSignature, memberKind, ConfigurationMemberAccessibility.ACCESSED); } - public void addMethod(String name, String internalSignature, ConfigurationMemberDeclaration memberKind, ConfigurationMemberAccessibility accessKind) { + public synchronized void addMethod(String name, String internalSignature, ConfigurationMemberDeclaration memberKind, ConfigurationMemberAccessibility accessKind) { ConfigurationMemberInfo kind = ConfigurationMemberInfo.get(memberKind, accessKind); boolean matchesAllSignatures = (internalSignature == null); if (ConfigurationMethod.isConstructorName(name) ? hasAllConstructors(memberKind, accessKind) : hasAllMethods(memberKind, accessKind)) { @@ -282,99 +306,66 @@ private boolean hasAllMethods(ConfigurationMemberDeclaration memberKind, Configu (memberKind.includes(ConfigurationMemberDeclaration.PUBLIC) && allPublicMethodsAccess.includes(accessKind)); } - public ConfigurationMemberInfo getMethodKindIfPresent(ConfigurationMethod method) { - return methods == null ? null : methods.get(method); - } - - public FieldInfo getFieldInfoIfPresent(String field) { - return fields == null ? null : fields.get(field); + public synchronized void setAllDeclaredClasses() { + allDeclaredClasses = true; } - public boolean haveAllDeclaredClasses() { - return allDeclaredClasses; + public synchronized void setAllPublicClasses() { + allPublicClasses = true; } - public boolean haveAllPublicClasses() { - return allPublicClasses; - } - - public void setAllDeclaredClasses() { - this.allDeclaredClasses = true; - } - - public void setAllPublicClasses() { - this.allPublicClasses = true; - } - - public boolean haveAllDeclaredFields() { - return allDeclaredFields; - } - - public boolean haveAllPublicFields() { - return allPublicFields; - } - - public void setAllDeclaredFields() { - this.allDeclaredFields = true; + public synchronized void setAllDeclaredFields() { + allDeclaredFields = true; removeFields(ConfigurationMemberDeclaration.DECLARED); } - public void setAllPublicFields() { - this.allPublicFields = true; + public synchronized void setAllPublicFields() { + allPublicFields = true; removeFields(ConfigurationMemberDeclaration.PUBLIC); } - public void setAllDeclaredMethods(ConfigurationMemberAccessibility accessKind) { - if (!this.allDeclaredMethodsAccess.includes(accessKind)) { - this.allDeclaredMethodsAccess = accessKind; + public synchronized void setAllDeclaredMethods(ConfigurationMemberAccessibility accessKind) { + if (!allDeclaredMethodsAccess.includes(accessKind)) { + allDeclaredMethodsAccess = accessKind; removeMethods(ConfigurationMemberDeclaration.DECLARED, accessKind, false); } } - public void setAllPublicMethods(ConfigurationMemberAccessibility accessKind) { - if (!this.allPublicMethodsAccess.includes(accessKind)) { - this.allPublicMethodsAccess = accessKind; + public synchronized void setAllPublicMethods(ConfigurationMemberAccessibility accessKind) { + if (!allPublicMethodsAccess.includes(accessKind)) { + allPublicMethodsAccess = accessKind; removeMethods(ConfigurationMemberDeclaration.PUBLIC, accessKind, false); } } - public ConfigurationMemberAccessibility getAllDeclaredConstructors() { - return allDeclaredConstructorsAccess; - } - - public ConfigurationMemberAccessibility getAllPublicConstructors() { - return allPublicConstructorsAccess; - } - - public void setAllDeclaredConstructors(ConfigurationMemberAccessibility accessKind) { - if (!this.allDeclaredConstructorsAccess.includes(accessKind)) { - this.allDeclaredConstructorsAccess = accessKind; + public synchronized void setAllDeclaredConstructors(ConfigurationMemberAccessibility accessKind) { + if (!allDeclaredConstructorsAccess.includes(accessKind)) { + allDeclaredConstructorsAccess = accessKind; removeMethods(ConfigurationMemberDeclaration.DECLARED, accessKind, true); } } - public void setAllPublicConstructors(ConfigurationMemberAccessibility accessKind) { - if (!this.allPublicConstructorsAccess.includes(accessKind)) { - this.allPublicConstructorsAccess = accessKind; + public synchronized void setAllPublicConstructors(ConfigurationMemberAccessibility accessKind) { + if (!allPublicConstructorsAccess.includes(accessKind)) { + allPublicConstructorsAccess = accessKind; removeMethods(ConfigurationMemberDeclaration.PUBLIC, accessKind, true); } } @Override - public void printJson(JsonWriter writer) throws IOException { + public synchronized void printJson(JsonWriter writer) throws IOException { writer.append('{').indent().newline(); - ConfigurationConditionPrintable.printConditionAttribute(condition, writer); - writer.quote("name").append(':').quote(qualifiedJavaName); - optionallyPrintJsonBoolean(writer, haveAllDeclaredFields(), "allDeclaredFields"); - optionallyPrintJsonBoolean(writer, haveAllPublicFields(), "allPublicFields"); + + optionallyPrintJsonBoolean(writer, allDeclaredFields, "allDeclaredFields"); + optionallyPrintJsonBoolean(writer, allPublicFields, "allPublicFields"); optionallyPrintJsonBoolean(writer, allDeclaredMethodsAccess == ConfigurationMemberAccessibility.ACCESSED, "allDeclaredMethods"); optionallyPrintJsonBoolean(writer, allPublicMethodsAccess == ConfigurationMemberAccessibility.ACCESSED, "allPublicMethods"); optionallyPrintJsonBoolean(writer, allDeclaredConstructorsAccess == ConfigurationMemberAccessibility.ACCESSED, "allDeclaredConstructors"); optionallyPrintJsonBoolean(writer, allPublicConstructorsAccess == ConfigurationMemberAccessibility.ACCESSED, "allPublicConstructors"); - optionallyPrintJsonBoolean(writer, haveAllDeclaredClasses(), "allDeclaredClasses"); - optionallyPrintJsonBoolean(writer, haveAllPublicClasses(), "allPublicClasses"); + optionallyPrintJsonBoolean(writer, allDeclaredClasses, "allDeclaredClasses"); + optionallyPrintJsonBoolean(writer, allPublicClasses, "allPublicClasses"); optionallyPrintJsonBoolean(writer, allDeclaredMethodsAccess == ConfigurationMemberAccessibility.QUERIED, "queryAllDeclaredMethods"); optionallyPrintJsonBoolean(writer, allPublicMethodsAccess == ConfigurationMemberAccessibility.QUERIED, "queryAllPublicMethods"); optionallyPrintJsonBoolean(writer, allDeclaredConstructorsAccess == ConfigurationMemberAccessibility.QUERIED, "queryAllDeclaredConstructors"); @@ -446,4 +437,45 @@ private static Map maybeRemove(Map fromMap, Consumer classes = new ConcurrentHashMap<>(); + private final ConcurrentMap classes = new ConcurrentHashMap<>(); private final Predicate shouldExcludeClassWithHash; public PredefinedClassesConfiguration(Path[] classDestinationDirs, Predicate shouldExcludeClassWithHash) { diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ProxyConfiguration.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ProxyConfiguration.java index 12f7af1d12bb..7131b47bcb8c 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ProxyConfiguration.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ProxyConfiguration.java @@ -28,6 +28,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.graalvm.nativeimage.impl.ConfigurationCondition; @@ -37,7 +38,7 @@ import com.oracle.svm.core.configure.ConditionalElement; public class ProxyConfiguration implements ConfigurationBase { - private final ConcurrentHashMap.KeySetView>, Boolean> interfaceLists = ConcurrentHashMap.newKeySet(); + private final Set>> interfaceLists = ConcurrentHashMap.newKeySet(); public ProxyConfiguration() { } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ResourceConfiguration.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ResourceConfiguration.java index 0ec183a4c191..5fb2b8aeb146 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ResourceConfiguration.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ResourceConfiguration.java @@ -25,6 +25,7 @@ package com.oracle.svm.configure.config; import java.io.IOException; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.regex.Pattern; @@ -65,9 +66,8 @@ public void addResourceBundles(ConfigurationCondition condition, String name) { } private final ConcurrentMap, Pattern> addedResources = new ConcurrentHashMap<>(); - private final ConcurrentMap, Pattern> ignoredResources = new ConcurrentHashMap<>(); - private final ConcurrentHashMap.KeySetView, Boolean> bundles = ConcurrentHashMap.newKeySet(); + private final Set> bundles = ConcurrentHashMap.newKeySet(); public ResourceConfiguration() { } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfiguration.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfiguration.java index a9347464e645..76c7ac6b3368 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfiguration.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfiguration.java @@ -46,7 +46,7 @@ public SerializationConfiguration() { } public SerializationConfiguration(SerializationConfiguration other) { - this.serializations.addAll(other.serializations); + serializations.addAll(other.serializations); } public void removeAll(SerializationConfiguration other) { diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/TypeConfiguration.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/TypeConfiguration.java index 529a1ab3bb83..6fdf91c2da0c 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/TypeConfiguration.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/TypeConfiguration.java @@ -28,7 +28,6 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.List; -import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -40,29 +39,18 @@ import com.oracle.svm.core.util.VMError; public class TypeConfiguration implements ConfigurationBase { - private final ConcurrentMap, ConfigurationType> types = new ConcurrentHashMap<>(); - - public TypeConfiguration() { + public static TypeConfiguration copyAndSubtract(TypeConfiguration config, TypeConfiguration toSubtract) { + TypeConfiguration copy = new TypeConfiguration(); + config.types.forEach((key, type) -> { + ConfigurationType subtractType = toSubtract.types.get(key); + copy.types.compute(key, (k, v) -> ConfigurationType.copyAndSubtract(type, subtractType)); + }); + return copy; } - public TypeConfiguration(TypeConfiguration other) { - for (Map.Entry, ConfigurationType> entry : other.types.entrySet()) { - types.put(entry.getKey(), new ConfigurationType(entry.getValue())); - } - } + private final ConcurrentMap, ConfigurationType> types = new ConcurrentHashMap<>(); - public void removeAll(TypeConfiguration other) { - for (Map.Entry, ConfigurationType> typeEntry : other.types.entrySet()) { - types.computeIfPresent(typeEntry.getKey(), (key, value) -> { - if (value.equals(typeEntry.getValue())) { - return null; - } - assert value.getCondition().equals(typeEntry.getValue().getCondition()); - assert value.getQualifiedJavaName().equals(typeEntry.getValue().getQualifiedJavaName()); - value.removeAll(typeEntry.getValue()); - return value.isEmpty() ? null : value; - }); - } + public TypeConfiguration() { } public ConfigurationType get(ConfigurationCondition condition, String qualifiedJavaName) { diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/TraceProcessor.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/TraceProcessor.java index 875e717b94dc..84ecb3eb49ae 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/TraceProcessor.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/TraceProcessor.java @@ -63,8 +63,7 @@ public TraceProcessor(AccessAdvisor accessAdvisor, TypeConfiguration jniConfigur public TypeConfiguration getJniConfiguration() { TypeConfiguration result = jniProcessor.getConfiguration(); if (omittedConfigProcessor != null) { - result = new TypeConfiguration(result); - result.removeAll(omittedConfigProcessor.jniProcessor.getConfiguration()); + result = TypeConfiguration.copyAndSubtract(result, omittedConfigProcessor.jniProcessor.getConfiguration()); } return result; } @@ -72,8 +71,7 @@ public TypeConfiguration getJniConfiguration() { public TypeConfiguration getReflectionConfiguration() { TypeConfiguration result = reflectionProcessor.getConfiguration(); if (omittedConfigProcessor != null) { - result = new TypeConfiguration(result); - result.removeAll(omittedConfigProcessor.reflectionProcessor.getConfiguration()); + result = TypeConfiguration.copyAndSubtract(result, omittedConfigProcessor.reflectionProcessor.getConfiguration()); } return result; } diff --git a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupUtil.java b/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupUtil.java index 52edc2745138..30cfe6cceefe 100644 --- a/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupUtil.java +++ b/substratevm/src/com.oracle.svm.core.containers/src/com/oracle/svm/core/containers/CgroupUtil.java @@ -51,6 +51,7 @@ static void unwrapIOExceptionAndRethrow(PrivilegedActionException pae) throws IO throw (Error) x; } + @SuppressWarnings({"deprecation"}) // doPrivileged is deprecated on JDK 17 static String readStringValue(CgroupSubsystemController controller, String param) throws IOException { PrivilegedExceptionAction pea = () -> new BufferedReader(new InputStreamReader(new FileInputStream(Paths.get(controller.path(), param).toString()), StandardCharsets.UTF_8)); @@ -63,6 +64,7 @@ static String readStringValue(CgroupSubsystemController controller, String param } } + @SuppressWarnings({"deprecation"}) // doPrivileged is deprecated on JDK 17 public static List readAllLinesPrivileged(Path path) throws IOException { PrivilegedExceptionAction pea = () -> new BufferedReader(new InputStreamReader(new FileInputStream(path.toString()), StandardCharsets.UTF_8)); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AbstractCollectionPolicy.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AbstractCollectionPolicy.java index eca546000dee..53791cba5714 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AbstractCollectionPolicy.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AbstractCollectionPolicy.java @@ -27,6 +27,8 @@ import java.util.concurrent.locks.ReentrantLock; import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; @@ -42,8 +44,10 @@ abstract class AbstractCollectionPolicy implements CollectionPolicy { + protected static final int MIN_SPACE_SIZE_IN_ALIGNED_CHUNKS = 8; protected static final int MAX_TENURING_THRESHOLD = 15; + @Platforms(Platform.HOSTED_ONLY.class) static int getMaxSurvivorSpaces(Integer userValue) { assert userValue == null || userValue >= 0; return (userValue != null) ? userValue : AbstractCollectionPolicy.MAX_TENURING_THRESHOLD; @@ -61,15 +65,12 @@ static int getMaxSurvivorSpaces(Integer userValue) { protected static final int DEFAULT_TIME_WEIGHT = 25; // -XX:AdaptiveTimeWeight /* Constants to compute defaults for values which can be set through existing options. */ - /** HotSpot: -XX:MaxHeapSize default without ergonomics. */ - protected static final UnsignedWord SMALL_HEAP_SIZE = WordFactory.unsigned(96 * 1024 * 1024); + protected static final UnsignedWord INITIAL_HEAP_SIZE = WordFactory.unsigned(128 * 1024 * 1024); protected static final int NEW_RATIO = 2; // HotSpot: -XX:NewRatio - protected static final int LARGE_MEMORY_MAX_HEAP_PERCENT = 25; // -XX:MaxRAMPercentage - protected static final int SMALL_MEMORY_MAX_HEAP_PERCENT = 50; // -XX:MinRAMPercentage - protected static final double INITIAL_HEAP_MEMORY_PERCENT = 1.5625; // -XX:InitialRAMPercentage protected final AdaptiveWeightedAverage avgYoungGenAlignedChunkFraction = new AdaptiveWeightedAverage(DEFAULT_TIME_WEIGHT); + private final int initialNewRatio; protected UnsignedWord survivorSize; protected UnsignedWord edenSize; protected UnsignedWord promoSize; @@ -79,8 +80,9 @@ static int getMaxSurvivorSpaces(Integer userValue) { protected volatile SizeParameters sizes; private final ReentrantLock sizesUpdateLock = new ReentrantLock(); - protected AbstractCollectionPolicy(int initialTenuringThreshold) { - tenuringThreshold = UninterruptibleUtils.Math.clamp(initialTenuringThreshold, 1, HeapParameters.getMaxSurvivorSpaces() + 1); + protected AbstractCollectionPolicy(int initialNewRatio, int initialTenuringThreshold) { + this.initialNewRatio = initialNewRatio; + this.tenuringThreshold = UninterruptibleUtils.Math.clamp(initialTenuringThreshold, 1, HeapParameters.getMaxSurvivorSpaces() + 1); } @Override @@ -93,23 +95,28 @@ public boolean shouldCollectOnAllocation() { } @Fold - static UnsignedWord minSpaceSize() { + static UnsignedWord getAlignment() { return HeapParameters.getAlignedHeapChunkSize(); } @Uninterruptible(reason = "Used in uninterruptible code.", mayBeInlined = true) static UnsignedWord alignUp(UnsignedWord size) { - return UnsignedUtils.roundUp(size, minSpaceSize()); + return UnsignedUtils.roundUp(size, getAlignment()); } @Uninterruptible(reason = "Used in uninterruptible code.", mayBeInlined = true) static UnsignedWord alignDown(UnsignedWord size) { - return UnsignedUtils.roundDown(size, minSpaceSize()); + return UnsignedUtils.roundDown(size, getAlignment()); } @Uninterruptible(reason = "Used in uninterruptible code.", mayBeInlined = true) static boolean isAligned(UnsignedWord size) { - return UnsignedUtils.isAMultiple(size, minSpaceSize()); + return UnsignedUtils.isAMultiple(size, getAlignment()); + } + + @Fold + static UnsignedWord minSpaceSize() { + return getAlignment().multiply(MIN_SPACE_SIZE_IN_ALIGNED_CHUNKS); } @Uninterruptible(reason = "Used in uninterruptible code.", mayBeInlined = true) @@ -133,7 +140,7 @@ protected void guaranteeSizeParametersInitialized() { public void updateSizeParameters() { PhysicalMemory.tryInitialize(); - SizeParameters params = computeSizeParameters(); + SizeParameters params = computeSizeParameters(sizes); SizeParameters previous = sizes; if (previous != null && params.equal(previous)) { return; // nothing to do @@ -238,12 +245,13 @@ public UnsignedWord getMinimumHeapSize() { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) protected abstract long gcCount(); - protected SizeParameters computeSizeParameters() { + protected SizeParameters computeSizeParameters(SizeParameters existing) { UnsignedWord addressSpaceSize = ReferenceAccess.singleton().getAddressSpaceSize(); - UnsignedWord minAllSpaces = minSpaceSize().multiply(2); // eden, old + UnsignedWord minYoungSpaces = minSpaceSize(); // eden if (HeapParameters.getMaxSurvivorSpaces() > 0) { - minAllSpaces = minAllSpaces.add(minSpaceSize().multiply(2)); // survivor from and to + minYoungSpaces = minYoungSpaces.add(minSpaceSize().multiply(2)); // survivor from and to } + UnsignedWord minAllSpaces = minYoungSpaces.add(minSpaceSize()); // old UnsignedWord maxHeap; long optionMax = SubstrateGCOptions.MaxHeapSize.getValue(); @@ -252,21 +260,9 @@ protected SizeParameters computeSizeParameters() { } else if (!PhysicalMemory.isInitialized()) { maxHeap = addressSpaceSize; } else { - UnsignedWord physicalMemorySize = PhysicalMemory.getCachedSize(); - if (HeapParameters.Options.MaximumHeapSizePercent.hasBeenSet(RuntimeOptionValues.singleton())) { - maxHeap = physicalMemorySize.unsignedDivide(100).multiply(HeapParameters.getMaximumHeapSizePercent()); - } else { - UnsignedWord reasonableMax = physicalMemorySize.unsignedDivide(100).multiply(AbstractCollectionPolicy.LARGE_MEMORY_MAX_HEAP_PERCENT); - UnsignedWord reasonableMin = physicalMemorySize.unsignedDivide(100).multiply(AbstractCollectionPolicy.SMALL_MEMORY_MAX_HEAP_PERCENT); - if (reasonableMin.belowThan(AbstractCollectionPolicy.SMALL_HEAP_SIZE)) { - // small physical memory, use a small fraction for the heap - reasonableMax = reasonableMin; - } else { - reasonableMax = UnsignedUtils.max(reasonableMax, AbstractCollectionPolicy.SMALL_HEAP_SIZE); - } - maxHeap = reasonableMax; - } + maxHeap = PhysicalMemory.getCachedSize().unsignedDivide(100).multiply(HeapParameters.getMaximumHeapSizePercent()); } + UnsignedWord unadjustedMaxHeap = maxHeap; maxHeap = UnsignedUtils.clamp(alignDown(maxHeap), minAllSpaces, alignDown(addressSpaceSize)); UnsignedWord maxYoung; @@ -278,16 +274,12 @@ protected SizeParameters computeSizeParameters() { } else { maxYoung = maxHeap.unsignedDivide(AbstractCollectionPolicy.NEW_RATIO + 1); } - maxYoung = UnsignedUtils.clamp(alignUp(maxYoung), minSpaceSize(), maxHeap); + maxYoung = UnsignedUtils.clamp(alignDown(maxYoung), minYoungSpaces, maxHeap.subtract(minSpaceSize())); - UnsignedWord maxOld = maxHeap.subtract(maxYoung); - maxOld = minSpaceSize(alignUp(maxOld)); + UnsignedWord maxOld = alignDown(maxHeap.subtract(maxYoung)); maxHeap = maxYoung.add(maxOld); - if (maxHeap.aboveThan(addressSpaceSize)) { - maxYoung = alignDown(maxYoung.subtract(minSpaceSize())); - maxHeap = maxYoung.add(maxOld); - VMError.guarantee(maxHeap.belowOrEqual(addressSpaceSize) && maxYoung.aboveOrEqual(minSpaceSize())); - } + VMError.guarantee(maxOld.aboveOrEqual(minSpaceSize()) && maxHeap.belowOrEqual(addressSpaceSize) && + (maxHeap.belowOrEqual(unadjustedMaxHeap) || unadjustedMaxHeap.belowThan(minAllSpaces))); UnsignedWord minHeap = WordFactory.zero(); long optionMin = SubstrateGCOptions.MinHeapSize.getValue(); @@ -296,19 +288,15 @@ protected SizeParameters computeSizeParameters() { } minHeap = UnsignedUtils.clamp(alignUp(minHeap), minAllSpaces, maxHeap); - UnsignedWord initialHeap; - if (PhysicalMemory.isInitialized()) { - initialHeap = UnsignedUtils.fromDouble(UnsignedUtils.toDouble(PhysicalMemory.getCachedSize()) / 100 * AbstractCollectionPolicy.INITIAL_HEAP_MEMORY_PERCENT); - } else { - initialHeap = AbstractCollectionPolicy.SMALL_HEAP_SIZE; - } + UnsignedWord initialHeap = AbstractCollectionPolicy.INITIAL_HEAP_SIZE; initialHeap = UnsignedUtils.clamp(alignUp(initialHeap), minHeap, maxHeap); UnsignedWord initialYoung; if (initialHeap.equal(maxHeap)) { initialYoung = maxYoung; } else { - initialYoung = UnsignedUtils.clamp(alignUp(initialHeap.unsignedDivide(AbstractCollectionPolicy.NEW_RATIO + 1)), minSpaceSize(), maxYoung); + initialYoung = initialHeap.unsignedDivide(initialNewRatio + 1); + initialYoung = UnsignedUtils.clamp(alignUp(initialYoung), minYoungSpaces, maxYoung); } UnsignedWord initialSurvivor = WordFactory.zero(); if (HeapParameters.getMaxSurvivorSpaces() > 0) { @@ -320,11 +308,13 @@ protected SizeParameters computeSizeParameters() { * generation, which we can exceed the (current) old gen size while copying during * collections. */ - initialSurvivor = minSpaceSize(alignUp(initialYoung.unsignedDivide(AbstractCollectionPolicy.INITIAL_SURVIVOR_RATIO))); + initialSurvivor = initialYoung.unsignedDivide(AbstractCollectionPolicy.INITIAL_SURVIVOR_RATIO); + initialSurvivor = minSpaceSize(alignDown(initialSurvivor)); } - UnsignedWord initialEden = minSpaceSize(alignUp(initialYoung.subtract(initialSurvivor.multiply(2)))); + UnsignedWord initialEden = initialYoung.subtract(initialSurvivor.multiply(2)); + initialEden = minSpaceSize(alignDown(initialEden)); - return new SizeParameters(maxHeap, maxYoung, initialHeap, initialEden, initialSurvivor, minHeap); + return SizeParameters.get(existing, maxHeap, maxYoung, initialHeap, initialEden, initialSurvivor, minHeap); } protected static final class SizeParameters { @@ -335,7 +325,15 @@ protected static final class SizeParameters { final UnsignedWord initialSurvivorSize; final UnsignedWord minHeapSize; - SizeParameters(UnsignedWord maxHeapSize, UnsignedWord maxYoungSize, UnsignedWord initialHeapSize, + static SizeParameters get(SizeParameters existing, UnsignedWord maxHeap, UnsignedWord maxYoung, UnsignedWord initialHeap, + UnsignedWord initialEden, UnsignedWord initialSurvivor, UnsignedWord minHeap) { + if (existing != null && existing.matches(maxHeap, maxYoung, initialHeap, initialEden, initialSurvivor, minHeap)) { + return existing; + } + return new SizeParameters(maxHeap, maxYoung, initialHeap, initialEden, initialSurvivor, minHeap); + } + + private SizeParameters(UnsignedWord maxHeapSize, UnsignedWord maxYoungSize, UnsignedWord initialHeapSize, UnsignedWord initialEdenSize, UnsignedWord initialSurvivorSize, UnsignedWord minHeapSize) { this.maxHeapSize = maxHeapSize; this.maxYoungSize = maxYoungSize; @@ -381,8 +379,13 @@ UnsignedWord maxOldSize() { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) boolean equal(SizeParameters other) { - return maxHeapSize.equal(other.maxHeapSize) && maxYoungSize.equal(other.maxYoungSize) && initialHeapSize.equal(other.initialHeapSize) && - initialEdenSize.equal(other.initialEdenSize) && initialSurvivorSize.equal(other.initialSurvivorSize) && minHeapSize.equal(other.minHeapSize); + return other == this || other.matches(maxHeapSize, maxYoungSize, initialHeapSize, initialEdenSize, initialSurvivorSize, minHeapSize); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + boolean matches(UnsignedWord maxHeap, UnsignedWord maxYoung, UnsignedWord initialHeap, UnsignedWord initialEden, UnsignedWord initialSurvivor, UnsignedWord minHeap) { + return maxHeapSize.equal(maxHeap) && maxYoungSize.equal(maxYoung) && initialHeapSize.equal(initialHeap) && + initialEdenSize.equal(initialEden) && initialSurvivorSize.equal(initialSurvivor) && minHeapSize.equal(minHeap); } } } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AdaptiveCollectionPolicy.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AdaptiveCollectionPolicy.java index a2746b0f0616..cdbe856d09dc 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AdaptiveCollectionPolicy.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AdaptiveCollectionPolicy.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.core.genscavenge; +import static com.oracle.svm.core.genscavenge.CollectionPolicy.shouldCollectYoungGenSeparately; + import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; @@ -94,11 +96,18 @@ final class AdaptiveCollectionPolicy extends AbstractCollectionPolicy { private static final boolean ADAPTIVE_SIZE_USE_COST_ESTIMATORS = true; private static final int ADAPTIVE_SIZE_POLICY_INITIALIZING_STEPS = ADAPTIVE_SIZE_POLICY_READY_THRESHOLD; /** The minimum increase in throughput in percent for expanding a space by 1% of its size. */ - private static final double ADAPTIVE_SIZE_ESTIMATOR_MIN_SIZE_THROUGHPUT_TRADEOFF = 0.8; + private static final double ADAPTIVE_SIZE_ESTIMATOR_MIN_SIZE_COST_TRADEOFF = 0.5; /** The effective number of most recent data points used by estimator (exponential decay). */ - private static final int ADAPTIVE_SIZE_COST_ESTIMATORS_HISTORY_LENGTH = ADAPTIVE_TIME_WEIGHT; + private static final int ADAPTIVE_SIZE_COST_ESTIMATORS_HISTORY_LENGTH = 12; /** Threshold for triggering a complete collection after repeated minor collections. */ private static final int CONSECUTIVE_MINOR_TO_MAJOR_COLLECTION_PAUSE_TIME_RATIO = 2; + /** + * When the GC cost of a generation is above this value, its estimator is ignored and sizes are + * increased to avoid starving the mutator. + */ + private static final double ADAPTIVE_SIZE_COST_ESTIMATOR_GC_COST_LIMIT = 0.5; + + private static final int INITIAL_NEW_RATIO = 1; // same size for young and old generation /* Constants derived from other constants. */ private static final double THROUGHPUT_GOAL = 1.0 - 1.0 / (1.0 + GC_TIME_RATIO); @@ -111,7 +120,7 @@ final class AdaptiveCollectionPolicy extends AbstractCollectionPolicy { private final AdaptivePaddedAverage avgPromoted = new AdaptivePaddedAverage(ADAPTIVE_SIZE_POLICY_WEIGHT, PROMOTED_PADDING, true); private final ReciprocalLeastSquareFit minorCostEstimator = new ReciprocalLeastSquareFit(ADAPTIVE_SIZE_COST_ESTIMATORS_HISTORY_LENGTH); private long minorCount; - private long latestMinorMutatorIntervalSeconds; + private long latestMinorMutatorIntervalNanos; private boolean youngGenPolicyIsReady; private UnsignedWord youngGenSizeIncrementSupplement = WordFactory.unsigned(YOUNG_GENERATION_SIZE_SUPPLEMENT); private long youngGenChangeForMinorThroughput; @@ -125,12 +134,12 @@ final class AdaptiveCollectionPolicy extends AbstractCollectionPolicy { private final ReciprocalLeastSquareFit majorCostEstimator = new ReciprocalLeastSquareFit(ADAPTIVE_SIZE_COST_ESTIMATORS_HISTORY_LENGTH); private long majorCount; private UnsignedWord oldGenSizeIncrementSupplement = WordFactory.unsigned(TENURED_GENERATION_SIZE_SUPPLEMENT); - private long latestMajorMutatorIntervalSeconds; + private long latestMajorMutatorIntervalNanos; private boolean oldSizeExceededInPreviousCollection; private long oldGenChangeForMajorThroughput; AdaptiveCollectionPolicy() { - super(INITIAL_TENURING_THRESHOLD); + super(INITIAL_NEW_RATIO, INITIAL_TENURING_THRESHOLD); } @Override @@ -142,15 +151,15 @@ public String getName() { public boolean shouldCollectCompletely(boolean followingIncrementalCollection) { // should_{attempt_scavenge,full_GC} guaranteeSizeParametersInitialized(); - if (!followingIncrementalCollection) { + if (!followingIncrementalCollection && shouldCollectYoungGenSeparately(true)) { /* - * Always do an incremental collection first because we expect most of the objects in - * the young generation to be garbage, and we can reuse their leftover chunks for - * copying the live objects in the old generation with fewer allocations. + * Default to always doing an incremental collection first because we expect most of the + * objects in the young generation to be garbage, and we can reuse their leftover chunks + * for copying the live objects in the old generation with fewer allocations. */ return false; } - if (oldSizeExceededInPreviousCollection) { + if (followingIncrementalCollection && oldSizeExceededInPreviousCollection) { /* * In the preceding incremental collection, we promoted objects to the old generation * beyond its current capacity to avoid a promotion failure, but due to the chunked @@ -181,16 +190,14 @@ public boolean shouldCollectCompletely(boolean followingIncrementalCollection) { return promotionEstimate.aboveThan(oldFree); } - private void updateAverages(UnsignedWord survivedChunkBytes, UnsignedWord survivorOverflowObjectBytes, UnsignedWord promotedObjectBytes) { - /* - * Adding the object bytes of overflowed survivor objects does not consider the overhead of - * partially filled chunks in the many survivor spaces, so it underestimates the necessary - * survivors capacity. However, this should self-correct as we expand the survivor space and - * reduce the tenuring age to avoid overflowing survivor objects in the first place. - */ - avgSurvived.sample(survivedChunkBytes.add(survivorOverflowObjectBytes)); + private void updateAverages(boolean isSurvivorOverflow, UnsignedWord survivedChunkBytes, UnsignedWord promotedChunkBytes) { + UnsignedWord survived = survivedChunkBytes; + if (isSurvivorOverflow) { + survived = survived.add(promotedChunkBytes); // guess + } + avgSurvived.sample(survived); - avgPromoted.sample(promotedObjectBytes); + avgPromoted.sample(promotedChunkBytes); } private void computeSurvivorSpaceSizeAndThreshold(boolean isSurvivorOverflow, UnsignedWord survivorLimit) { @@ -232,9 +239,12 @@ private void computeSurvivorSpaceSizeAndThreshold(boolean isSurvivorOverflow, Un private void computeEdenSpaceSize() { boolean expansionReducesCost = true; // general assumption - boolean useEstimator = ADAPTIVE_SIZE_USE_COST_ESTIMATORS && youngGenChangeForMinorThroughput > ADAPTIVE_SIZE_POLICY_INITIALIZING_STEPS; - if (useEstimator) { - expansionReducesCost = minorCostEstimator.getSlope(UnsignedUtils.toDouble(edenSize)) <= 0; + if (shouldUseEstimator(youngGenChangeForMinorThroughput, minorGcCost())) { + expansionReducesCost = expansionSignificantlyReducesCost(minorCostEstimator, edenSize); + /* + * Note that if the estimator thinks expanding does not lead to significant improvement, + * shrink so to not get stuck in a supposed optimum and to keep collecting data points. + */ } UnsignedWord desiredEdenSize = edenSize; @@ -245,16 +255,9 @@ private void computeEdenSpaceSize() { assert scaleByRatio >= 0 && scaleByRatio <= 1; UnsignedWord scaledEdenHeapDelta = UnsignedUtils.fromDouble(scaleByRatio * UnsignedUtils.toDouble(edenHeapDelta)); - expansionReducesCost = !useEstimator || expansionSignificantlyReducesCost(minorCostEstimator, edenSize, scaledEdenHeapDelta); - if (expansionReducesCost) { - desiredEdenSize = alignUp(desiredEdenSize.add(scaledEdenHeapDelta)); - desiredEdenSize = UnsignedUtils.max(desiredEdenSize, edenSize); - youngGenChangeForMinorThroughput++; - } - /* - * If the estimator says expanding by delta does not lead to a significant improvement, - * shrink so to not get stuck in a supposed optimum and to keep collecting data points. - */ + desiredEdenSize = alignUp(desiredEdenSize.add(scaledEdenHeapDelta)); + desiredEdenSize = UnsignedUtils.max(desiredEdenSize, edenSize); + youngGenChangeForMinorThroughput++; } if (!expansionReducesCost || (USE_ADAPTIVE_SIZE_POLICY_FOOTPRINT_GOAL && youngGenPolicyIsReady && adjustedMutatorCost() >= THROUGHPUT_GOAL)) { UnsignedWord desiredSum = edenSize.add(promoSize); @@ -275,20 +278,21 @@ private void computeEdenSpaceSize() { edenSize = desiredEdenSize; } - private static boolean expansionSignificantlyReducesCost(ReciprocalLeastSquareFit estimator, UnsignedWord size, UnsignedWord delta) { + private static boolean shouldUseEstimator(long genChangeForThroughput, double cost) { + return ADAPTIVE_SIZE_USE_COST_ESTIMATORS && genChangeForThroughput > ADAPTIVE_SIZE_POLICY_INITIALIZING_STEPS && cost <= ADAPTIVE_SIZE_COST_ESTIMATOR_GC_COST_LIMIT; + } + + private static boolean expansionSignificantlyReducesCost(ReciprocalLeastSquareFit estimator, UnsignedWord size) { double x0 = UnsignedUtils.toDouble(size); - double x0Throughput = 1 - estimator.estimate(x0); - if (x0 == 0 || x0Throughput == 0) { // division by zero below - return false; - } - double x1 = x0 + UnsignedUtils.toDouble(delta); - double x1Throughput = 1 - estimator.estimate(x1); - if (x0 >= x1 || x0Throughput >= x1Throughput) { + double deltax = (1.01 - 1) * x0; + if (deltax == 0) { // division by zero below return false; } - double min = (x1 / x0 - 1) * ADAPTIVE_SIZE_ESTIMATOR_MIN_SIZE_THROUGHPUT_TRADEOFF; - double estimated = x1Throughput / x0Throughput - 1; - return (estimated >= min); + double y0 = estimator.estimate(x0); + double y1 = y0 * (1 - 0.01 * ADAPTIVE_SIZE_ESTIMATOR_MIN_SIZE_COST_TRADEOFF); + double minSlope = (y1 - y0) / deltax; + double estimatedSlope = estimator.getSlope(x0); + return estimatedSlope <= minSlope; } private static UnsignedWord adjustEdenForFootprint(UnsignedWord curEden, UnsignedWord desiredSum) { @@ -299,7 +303,7 @@ private static UnsignedWord adjustEdenForFootprint(UnsignedWord curEden, Unsigne UnsignedWord reducedSize = curEden.subtract(change); assert reducedSize.belowOrEqual(curEden); - return alignUp(reducedSize); + return alignDown(reducedSize); } private static UnsignedWord scaleDown(UnsignedWord change, UnsignedWord part, UnsignedWord total) { @@ -346,6 +350,12 @@ private double majorGcCost() { } private double gcCost() { + /* + * Because we're dealing with averages, gcCost() can be larger than 1.0 if just the sum of + * the minor cost and the major cost is used. Worse than that is the fact that the minor + * cost and the major cost each tend toward 1.0 in the extreme of high GC costs. Limit the + * value of gcCost() to 1.0 so that the mutator cost stays non-negative. + */ double cost = Math.min(1, minorGcCost() + majorGcCost()); assert cost >= 0 : "Both minor and major costs are non-negative"; return cost; @@ -360,22 +370,17 @@ private static UnsignedWord spaceIncrement(UnsignedWord curSize, UnsignedWord pe } private double secondsSinceMajorGc() { // time_since_major_gc - majorTimer.close(); - try { - return TimeUtils.nanosToSecondsDouble(majorTimer.getMeasuredNanos()); - } finally { - majorTimer.open(); - } + return TimeUtils.nanosToSecondsDouble(System.nanoTime() - majorTimer.getOpenedTime()); } @Override - public void onCollectionBegin(boolean completeCollection) { // {major,minor}_collection_begin + public void onCollectionBegin(boolean completeCollection, long requestingNanoTime) { // {major,minor}_collection_begin Timer timer = completeCollection ? majorTimer : minorTimer; - timer.close(); + timer.closeAt(requestingNanoTime); if (completeCollection) { - latestMajorMutatorIntervalSeconds = timer.getMeasuredNanos(); + latestMajorMutatorIntervalNanos = timer.getMeasuredNanos(); } else { - latestMinorMutatorIntervalSeconds = timer.getMeasuredNanos(); + latestMinorMutatorIntervalNanos = timer.getMeasuredNanos(); } // Capture the fraction of bytes in aligned chunks at the start to include all allocated @@ -397,13 +402,13 @@ public void onCollectionEnd(boolean completeCollection, GCCause cause) { // {maj if (completeCollection) { updateCollectionEndAverages(avgMajorGcCost, avgMajorPause, majorCostEstimator, avgMajorIntervalSeconds, - cause, latestMajorMutatorIntervalSeconds, timer.getMeasuredNanos(), promoSize); + cause, latestMajorMutatorIntervalNanos, timer.getMeasuredNanos(), promoSize); majorCount++; minorCountSinceMajorCollection = 0; } else { updateCollectionEndAverages(avgMinorGcCost, avgMinorPause, minorCostEstimator, null, - cause, latestMinorMutatorIntervalSeconds, timer.getMeasuredNanos(), edenSize); + cause, latestMinorMutatorIntervalNanos, timer.getMeasuredNanos(), edenSize); minorCount++; minorCountSinceMajorCollection++; @@ -419,24 +424,29 @@ public void onCollectionEnd(boolean completeCollection, GCCause cause) { // {maj UnsignedWord oldLive = accounting.getOldGenerationAfterChunkBytes(); oldSizeExceededInPreviousCollection = oldLive.aboveThan(oldSize); - /* - * Update the averages that survivor space and tenured space sizes are derived from. Note - * that we use chunk bytes (not object bytes) for the survivors. This is because they are - * kept in many spaces (one for each age), which potentially results in significant overhead - * from chunks that may only be partially filled, especially when the heap is small. Using - * chunk bytes here ensures that the needed survivor capacity is not underestimated. - */ - UnsignedWord survivedChunkBytes = HeapImpl.getHeapImpl().getYoungGeneration().getSurvivorChunkBytes(); - UnsignedWord survivorOverflowObjectBytes = accounting.getSurvivorOverflowObjectBytes(); - UnsignedWord tenuredObjBytes = accounting.getTenuredObjectBytes(); // includes overflowed - updateAverages(survivedChunkBytes, survivorOverflowObjectBytes, tenuredObjBytes); + if (!completeCollection) { + /* + * Update the averages that survivor space and tenured space sizes are derived from. + * Note that we use chunk bytes (not object bytes) for the survivors. This is because + * they are kept in many spaces (one for each age), which potentially results in + * significant overhead from chunks that may only be partially filled, especially when + * the heap is small. Using chunk bytes here ensures that the needed survivor capacity + * is not underestimated. + */ + boolean survivorOverflow = accounting.hasLastIncrementalCollectionOverflowedSurvivors(); + UnsignedWord survivedChunkBytes = HeapImpl.getHeapImpl().getYoungGeneration().getSurvivorChunkBytes(); + UnsignedWord tenuredChunkBytes = accounting.getLastIncrementalCollectionPromotedChunkBytes(); + updateAverages(survivorOverflow, survivedChunkBytes, tenuredChunkBytes); - computeSurvivorSpaceSizeAndThreshold(survivorOverflowObjectBytes.aboveThan(0), sizes.maxSurvivorSize()); - computeEdenSpaceSize(); - if (completeCollection) { - computeOldGenSpaceSize(oldLive); + computeSurvivorSpaceSizeAndThreshold(survivorOverflow, sizes.maxSurvivorSize()); + } + if (shouldUpdateStats(cause)) { + computeEdenSpaceSize(); + if (completeCollection) { + computeOldGenSpaceSize(oldLive); + } + decaySupplementalGrowth(completeCollection); } - decaySupplementalGrowth(completeCollection); } private void computeOldGenSpaceSize(UnsignedWord oldLive) { // compute_old_gen_free_space @@ -447,9 +457,12 @@ private void computeOldGenSpaceSize(UnsignedWord oldLive) { // compute_old_gen_f promoLimit = alignDown(UnsignedUtils.max(promoSize, promoLimit)); boolean expansionReducesCost = true; // general assumption - boolean useEstimator = ADAPTIVE_SIZE_USE_COST_ESTIMATORS && oldGenChangeForMajorThroughput > ADAPTIVE_SIZE_POLICY_INITIALIZING_STEPS; - if (useEstimator) { - expansionReducesCost = majorCostEstimator.getSlope(UnsignedUtils.toDouble(promoSize)) <= 0; + if (shouldUseEstimator(oldGenChangeForMajorThroughput, majorGcCost())) { + expansionReducesCost = expansionSignificantlyReducesCost(majorCostEstimator, promoSize); + /* + * Note that if the estimator thinks expanding does not lead to significant improvement, + * shrink so to not get stuck in a supposed optimum and to keep collecting data points. + */ } UnsignedWord desiredPromoSize = promoSize; @@ -460,16 +473,9 @@ private void computeOldGenSpaceSize(UnsignedWord oldLive) { // compute_old_gen_f assert scaleByRatio >= 0 && scaleByRatio <= 1; UnsignedWord scaledPromoHeapDelta = UnsignedUtils.fromDouble(scaleByRatio * UnsignedUtils.toDouble(promoHeapDelta)); - expansionReducesCost = !useEstimator || expansionSignificantlyReducesCost(majorCostEstimator, promoSize, scaledPromoHeapDelta); - if (expansionReducesCost) { - desiredPromoSize = alignUp(promoSize.add(scaledPromoHeapDelta)); - desiredPromoSize = UnsignedUtils.max(desiredPromoSize, promoSize); - oldGenChangeForMajorThroughput++; - } - /* - * If the estimator says expanding by delta does not lead to a significant improvement, - * shrink so to not get stuck in a supposed optimum and to keep collecting data points. - */ + desiredPromoSize = alignUp(promoSize.add(scaledPromoHeapDelta)); + desiredPromoSize = UnsignedUtils.max(desiredPromoSize, promoSize); + oldGenChangeForMajorThroughput++; } if (!expansionReducesCost || (USE_ADAPTIVE_SIZE_POLICY_FOOTPRINT_GOAL && youngGenPolicyIsReady && adjustedMutatorCost() >= THROUGHPUT_GOAL)) { UnsignedWord desiredSum = edenSize.add(promoSize); @@ -499,7 +505,7 @@ private static UnsignedWord adjustPromoForFootprint(UnsignedWord curPromo, Unsig UnsignedWord reducedSize = curPromo.subtract(change); assert reducedSize.belowOrEqual(curPromo); - return alignUp(reducedSize); + return alignDown(reducedSize); } private static UnsignedWord promoDecrement(UnsignedWord curPromo) { @@ -530,9 +536,13 @@ private void decaySupplementalGrowth(boolean completeCollection) { } } + private static boolean shouldUpdateStats(GCCause cause) { // should_update_{eden,promo}_stats + return cause == GenScavengeGCCause.OnAllocation || USE_ADAPTIVE_SIZE_POLICY_WITH_SYSTEM_GC; + } + private static void updateCollectionEndAverages(AdaptiveWeightedAverage costAverage, AdaptivePaddedAverage pauseAverage, ReciprocalLeastSquareFit costEstimator, AdaptiveWeightedAverage intervalSeconds, GCCause cause, long mutatorNanos, long pauseNanos, UnsignedWord sizeBytes) { - if (cause == GenScavengeGCCause.OnAllocation || USE_ADAPTIVE_SIZE_POLICY_WITH_SYSTEM_GC) { + if (shouldUpdateStats(cause)) { double cost = 0; double mutatorInSeconds = TimeUtils.nanosToSecondsDouble(mutatorNanos); double pauseInSeconds = TimeUtils.nanosToSecondsDouble(pauseNanos); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/BasicCollectionPolicies.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/BasicCollectionPolicies.java index 5145441da672..29b6987bd642 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/BasicCollectionPolicies.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/BasicCollectionPolicies.java @@ -26,8 +26,11 @@ import static com.oracle.svm.core.genscavenge.BasicCollectionPolicies.Options.AllocationBeforePhysicalMemorySize; import static com.oracle.svm.core.genscavenge.BasicCollectionPolicies.Options.PercentTimeInIncrementalCollection; +import static com.oracle.svm.core.genscavenge.CollectionPolicy.shouldCollectYoungGenSeparately; import org.graalvm.compiler.options.Option; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; @@ -50,6 +53,7 @@ public static class Options { public static final HostedOptionKey AllocationBeforePhysicalMemorySize = new HostedOptionKey<>(1L * 1024L * 1024L); } + @Platforms(Platform.HOSTED_ONLY.class) static int getMaxSurvivorSpaces(Integer userValue) { assert userValue == null || userValue >= 0; return 0; // override option (if set): survivor spaces not supported @@ -166,7 +170,7 @@ public int getTenuringAge() { } @Override - public void onCollectionBegin(boolean completeCollection) { + public void onCollectionBegin(boolean completeCollection, long requestingNanoTime) { } @Override @@ -191,6 +195,9 @@ public static final class OnlyCompletely extends BasicPolicy { @Override public boolean shouldCollectCompletely(boolean followingIncrementalCollection) { + if (!followingIncrementalCollection && shouldCollectYoungGenSeparately(false)) { + return false; + } return true; } @@ -226,7 +233,7 @@ public static final class BySpaceAndTime extends BasicPolicy { @Override public boolean shouldCollectCompletely(boolean followingIncrementalCollection) { - if (followingIncrementalCollection && !HeapParameters.Options.CollectYoungGenerationSeparately.getValue()) { + if (!followingIncrementalCollection && shouldCollectYoungGenSeparately(false)) { return false; } return estimateUsedHeapAtNextIncrementalCollection().aboveThan(getMaximumHeapSize()) || diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CollectionPolicy.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CollectionPolicy.java index 38970e76c7b8..581ea291de19 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CollectionPolicy.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CollectionPolicy.java @@ -39,7 +39,7 @@ public interface CollectionPolicy { final class Options { @Option(help = "The garbage collection policy, either Adaptive (default) or BySpaceAndTime.")// - public static final HostedOptionKey InitialCollectionPolicy = new HostedOptionKey<>("BySpaceAndTime"); + public static final HostedOptionKey InitialCollectionPolicy = new HostedOptionKey<>("Adaptive"); } @Platforms(Platform.HOSTED_ONLY.class) @@ -86,6 +86,11 @@ static int getMaxSurvivorSpaces(Integer userValue) { return BasicCollectionPolicies.getMaxSurvivorSpaces(userValue); } + static boolean shouldCollectYoungGenSeparately(boolean defaultValue) { + Boolean optionValue = HeapParameters.Options.CollectYoungGenerationSeparately.getValue(); + return (optionValue != null) ? optionValue : defaultValue; + } + String getName(); /** @@ -97,9 +102,9 @@ static int getMaxSurvivorSpaces(Integer userValue) { /** * (Re)computes minimum/maximum/initial sizes of space based on the available - * {@linkplain PhysicalMemory physical memory} and current runtime option values. This method is - * called after slow-path allocation (of a TLAB or a large object) and so allocation is allowed, - * but can trigger a collection. + * {@linkplain PhysicalMemory physical memory} and current runtime option values. This method + * can be called directly or after a slow-path allocation (of a TLAB or a large object) and so + * allocation is allowed, but may trigger a collection. */ void updateSizeParameters(); @@ -165,7 +170,7 @@ static int getMaxSurvivorSpaces(Integer userValue) { int getTenuringAge(); /** Called at the beginning of a collection, in the safepoint operation. */ - void onCollectionBegin(boolean completeCollection); + void onCollectionBegin(boolean completeCollection, long requestingNanoTime); /** Called before the end of a collection, in the safepoint operation. */ void onCollectionEnd(boolean completeCollection, GCCause cause); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCAccounting.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCAccounting.java index 0533458c1cf6..7b312f0fc325 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCAccounting.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCAccounting.java @@ -30,7 +30,6 @@ import org.graalvm.word.WordFactory; import com.oracle.svm.core.annotate.AlwaysInline; -import com.oracle.svm.core.hub.LayoutEncoding; import com.oracle.svm.core.log.Log; /** @@ -47,8 +46,8 @@ public final class GCAccounting { private long completeCollectionTotalNanos = 0; private UnsignedWord collectedTotalChunkBytes = WordFactory.zero(); private UnsignedWord allocatedChunkBytes = WordFactory.zero(); - private UnsignedWord tenuredObjectBytes = WordFactory.zero(); - private UnsignedWord survivorOverflowObjectBytes = WordFactory.zero(); + private UnsignedWord lastIncrementalCollectionPromotedChunkBytes = WordFactory.zero(); + private boolean lastIncrementalCollectionOverflowedSurvivors = false; /* Before and after measures. */ private UnsignedWord youngChunkBytesBefore = WordFactory.zero(); @@ -113,15 +112,15 @@ UnsignedWord getYoungChunkBytesAfter() { return youngChunkBytesAfter; } - UnsignedWord getTenuredObjectBytes() { - return tenuredObjectBytes; + UnsignedWord getLastIncrementalCollectionPromotedChunkBytes() { + return lastIncrementalCollectionPromotedChunkBytes; } - UnsignedWord getSurvivorOverflowObjectBytes() { - return survivorOverflowObjectBytes; + public boolean hasLastIncrementalCollectionOverflowedSurvivors() { + return lastIncrementalCollectionOverflowedSurvivors; } - void beforeCollection() { + void beforeCollection(boolean completeCollection) { Log trace = Log.noopLog().string("[GCImpl.Accounting.beforeCollection:").newline(); /* Gather some space statistics. */ HeapImpl heap = HeapImpl.getHeapImpl(); @@ -138,8 +137,9 @@ void beforeCollection() { oldObjectBytesBefore = oldSpace.computeObjectBytes(); allocatedObjectBytes = allocatedObjectBytes.add(edenObjectBytesBefore); } - tenuredObjectBytes = WordFactory.zero(); - survivorOverflowObjectBytes = WordFactory.zero(); + if (!completeCollection) { + lastIncrementalCollectionOverflowedSurvivors = false; + } trace.string(" youngChunkBytesBefore: ").unsigned(youngChunkBytesBefore) .string(" oldChunkBytesBefore: ").unsigned(oldChunkBytesBefore); trace.string("]").newline(); @@ -147,12 +147,8 @@ void beforeCollection() { /** Called after an object has been promoted from the young generation to the old generation. */ @AlwaysInline("GC performance") - void onObjectTenured(Object result, boolean survivorOverflow) { - UnsignedWord size = LayoutEncoding.getSizeFromObject(result); - tenuredObjectBytes = tenuredObjectBytes.add(size); - if (survivorOverflow) { - survivorOverflowObjectBytes = survivorOverflowObjectBytes.add(size); - } + void onSurvivorOverflowed() { + lastIncrementalCollectionOverflowedSurvivors = true; } void afterCollection(boolean completeCollection, Timer collectionTimer) { @@ -172,6 +168,7 @@ private void afterIncrementalCollection(Timer collectionTimer) { */ incrementalCollectionCount += 1; afterCollectionCommon(); + lastIncrementalCollectionPromotedChunkBytes = oldChunkBytesAfter.subtract(oldChunkBytesBefore); incrementalCollectionTotalNanos += collectionTimer.getMeasuredNanos(); trace.string(" incrementalCollectionCount: ").signed(incrementalCollectionCount) .string(" oldChunkBytesAfter: ").unsigned(oldChunkBytesAfter) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java index 8d8c7ff1fe6c..d3371be956c6 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java @@ -168,6 +168,7 @@ boolean collectWithoutAllocating(GCCause cause, boolean forceFullGC) { data.setNativeVMOperation(collectOperation); data.setCauseId(cause.getId()); data.setRequestingEpoch(getCollectionEpoch()); + data.setRequestingNanoTime(System.nanoTime()); data.setForceFullGC(forceFullGC); enqueueCollectOperation(data); return data.getOutOfMemory(); @@ -179,11 +180,11 @@ private void enqueueCollectOperation(CollectionVMOperationData data) { } /** The body of the VMOperation to do the collection. */ - private boolean collectOperation(GCCause cause, UnsignedWord requestingEpoch, boolean forceFullGC) { + private void collectOperation(CollectionVMOperationData data) { assert VMOperation.isGCInProgress() : "Collection should be a VMOperation."; - assert getCollectionEpoch().equal(requestingEpoch); + assert getCollectionEpoch().equal(data.getRequestingEpoch()); - timers.mutator.close(); + timers.mutator.closeAt(data.getRequestingNanoTime()); startCollectionOrExit(); timers.resetAllExceptMutator(); @@ -192,31 +193,29 @@ private boolean collectOperation(GCCause cause, UnsignedWord requestingEpoch, bo /* Flush all TLAB chunks to eden. */ ThreadLocalAllocation.disableAndFlushForAllThreads(); + GCCause cause = GCCause.fromId(data.getCauseId()); printGCBefore(cause.getName()); - boolean outOfMemory = collectImpl(cause, forceFullGC); - HeapImpl.getHeapImpl().getAccounting().setEdenAndYoungGenBytes(WordFactory.unsigned(0), accounting.getYoungChunkBytesAfter()); + boolean outOfMemory = collectImpl(cause, data.getRequestingNanoTime(), data.getForceFullGC()); printGCAfter(cause.getName()); finishCollection(); timers.mutator.open(); - return outOfMemory; + data.setOutOfMemory(outOfMemory); } - private boolean collectImpl(GCCause cause, boolean forceFullGC) { + private boolean collectImpl(GCCause cause, long requestingNanoTime, boolean forceFullGC) { boolean outOfMemory; - precondition(); - verifyBeforeGC(); NoAllocationVerifier nav = noAllocationVerifier.open(); try { - outOfMemory = doCollectImpl(cause, forceFullGC); + outOfMemory = doCollectImpl(cause, requestingNanoTime, forceFullGC, false); if (outOfMemory) { // Avoid running out of memory with a full GC that reclaims softly reachable objects ReferenceObjectProcessing.setSoftReferencesAreWeak(true); try { - outOfMemory = doCollectImpl(cause, true); + outOfMemory = doCollectImpl(cause, requestingNanoTime, true, true); } finally { ReferenceObjectProcessing.setSoftReferencesAreWeak(false); } @@ -225,25 +224,23 @@ private boolean collectImpl(GCCause cause, boolean forceFullGC) { nav.close(); } - verifyAfterGC(); postcondition(); return outOfMemory; } - private boolean doCollectImpl(GCCause cause, boolean forceFullGC) { + private boolean doCollectImpl(GCCause cause, long requestingNanoTime, boolean forceFullGC, boolean forceNoIncremental) { CommittedMemoryProvider.get().beforeGarbageCollection(); - boolean incremental = HeapParameters.Options.CollectYoungGenerationSeparately.getValue() || - (!forceFullGC && !policy.shouldCollectCompletely(false)); + boolean incremental = !forceNoIncremental && !policy.shouldCollectCompletely(false); boolean outOfMemory = false; if (incremental) { - outOfMemory = doCollectOnce(cause, false, false); + outOfMemory = doCollectOnce(cause, requestingNanoTime, false, false); } - if (!incremental || outOfMemory || forceFullGC || policy.shouldCollectCompletely(true)) { + if (!incremental || outOfMemory || forceFullGC || policy.shouldCollectCompletely(incremental)) { if (incremental) { // uncommit unaligned chunks CommittedMemoryProvider.get().afterGarbageCollection(); } - outOfMemory = doCollectOnce(cause, true, incremental); + outOfMemory = doCollectOnce(cause, requestingNanoTime, true, incremental); } HeapImpl.getChunkProvider().freeExcessAlignedChunks(); @@ -251,20 +248,25 @@ private boolean doCollectImpl(GCCause cause, boolean forceFullGC) { return outOfMemory; } - private boolean doCollectOnce(GCCause cause, boolean complete, boolean followsIncremental) { + private boolean doCollectOnce(GCCause cause, long requestingNanoTime, boolean complete, boolean followsIncremental) { assert !followsIncremental || complete : "An incremental collection cannot be followed by another incremental collection"; completeCollection = complete; - accounting.beforeCollection(); - policy.onCollectionBegin(completeCollection); + accounting.beforeCollection(completeCollection); + policy.onCollectionBegin(completeCollection, requestingNanoTime); Timer collectionTimer = timers.collection.open(); try { - scavenge(!complete, followsIncremental); + if (!followsIncremental) { // we would have verified the heap after the incremental GC + verifyBeforeGC(); + } + scavenge(!complete); + verifyAfterGC(); } finally { collectionTimer.close(); } + HeapImpl.getHeapImpl().getAccounting().setEdenAndYoungGenBytes(WordFactory.zero(), accounting.getYoungChunkBytesAfter()); accounting.afterCollection(completeCollection, collectionTimer); policy.onCollectionEnd(completeCollection, cause); @@ -368,7 +370,7 @@ private void printGCAfter(String cause) { UnsignedWord sizeAfter = getChunkBytes(); printGCLog.string("["); if (HeapOptions.PrintGCTimeStamps.getValue()) { - long finishNanos = timers.collection.getFinish(); + long finishNanos = timers.collection.getClosedTime(); printGCLog.unsigned(TimeUtils.roundNanosToMillis(Timer.getTimeSinceFirstAllocation(finishNanos))).string(" msec: "); } printGCLog.string(completeCollection ? "Full GC" : "Incremental GC"); @@ -381,7 +383,7 @@ private void printGCAfter(String cause) { } if (SubstrateGCOptions.VerboseGC.getValue()) { verboseGCLog.string(" ["); - long finishNanos = timers.collection.getFinish(); + long finishNanos = timers.collection.getClosedTime(); if (HeapOptions.PrintGCTimeStamps.getValue()) { verboseGCLog.unsigned(TimeUtils.roundNanosToMillis(Timer.getTimeSinceFirstAllocation(finishNanos))).string(" msec: "); } else { @@ -493,7 +495,7 @@ public boolean isCompleteCollection() { } /** Scavenge, either from dirty roots or from all roots, and process discovered references. */ - private void scavenge(boolean incremental, boolean followingIncremental) { + private void scavenge(boolean incremental) { GreyToBlackObjRefVisitor.Counters counters = greyToBlackObjRefVisitor.openCounters(); try { Timer rootScanTimer = timers.rootScan.open(); @@ -501,7 +503,7 @@ private void scavenge(boolean incremental, boolean followingIncremental) { if (incremental) { cheneyScanFromDirtyRoots(); } else { - cheneyScanFromRoots(followingIncremental); + cheneyScanFromRoots(); } } finally { rootScanTimer.close(); @@ -574,7 +576,7 @@ private void cleanRuntimeCodeCache() { } } - private void cheneyScanFromRoots(boolean followingIncremental) { + private void cheneyScanFromRoots() { Timer cheneyScanFromRootsTimer = timers.cheneyScanFromRoots.open(); try { /* Take a snapshot of the heap so that I can visit all the promoted Objects. */ @@ -583,23 +585,7 @@ private void cheneyScanFromRoots(boolean followingIncremental) { * Objects into each of the blackening methods, or even put them around individual * Object reference visits. */ - prepareForPromotion(); - - if (followingIncremental) { - /* - * We just finished an incremental collection, so we will not be able to reclaim any - * young objects and do not need to copy them (and do not want to age or tenure them - * in the process). We still need to scan them for roots into the old generation. - * - * There is potential trouble with this: if objects in the young generation are - * reachable only from garbage objects in the old generation, the young objects are - * not reclaimed during this collection. If there is a cycle in which the young - * objects in turn keep the old objects alive, none of the objects can be reclaimed - * until the young objects are eventually tenured, or until a single complete - * collection is done before we would run out of memory. - */ - HeapImpl.getHeapImpl().getYoungGeneration().emptyFromSpacesIntoToSpaces(); - } + prepareForPromotion(false); /* * Make sure all chunks with pinned objects are in toSpace, and any formerly pinned @@ -623,14 +609,14 @@ private void cheneyScanFromRoots(boolean followingIncremental) { blackenImageHeapRoots(); /* Visit all the Objects promoted since the snapshot. */ - scanGreyObjects(); + scanGreyObjects(false); if (DeoptimizationSupport.enabled()) { /* Visit the runtime compiled code, now that we know all the reachable objects. */ walkRuntimeCodeCache(); /* Visit all objects that became reachable because of the compiled code. */ - scanGreyObjects(); + scanGreyObjects(false); } greyToBlackObjectVisitor.reset(); @@ -656,7 +642,7 @@ private void cheneyScanFromDirtyRoots() { * Objects into each of the blackening methods, or even put them around individual * Object reference visits. */ - prepareForPromotion(); + prepareForPromotion(true); /* * Make sure any released objects are in toSpace (because this is an incremental @@ -689,14 +675,14 @@ private void cheneyScanFromDirtyRoots() { blackenDirtyImageHeapRoots(); /* Visit all the Objects promoted since the snapshot, transitively. */ - scanGreyObjects(); + scanGreyObjects(true); if (DeoptimizationSupport.enabled()) { /* Visit the runtime compiled code, now that we know all the reachable objects. */ walkRuntimeCodeCache(); /* Visit all objects that became reachable because of the compiled code. */ - scanGreyObjects(); + scanGreyObjects(true); } greyToBlackObjectVisitor.reset(); @@ -944,28 +930,38 @@ private void blackenDirtyCardRoots() { } } - private static void prepareForPromotion() { + private static void prepareForPromotion(boolean isIncremental) { HeapImpl heap = HeapImpl.getHeapImpl(); heap.getOldGeneration().prepareForPromotion(); - heap.getYoungGeneration().prepareForPromotion(); + if (isIncremental) { + heap.getYoungGeneration().prepareForPromotion(); + } } - private void scanGreyObjects() { - HeapImpl heap = HeapImpl.getHeapImpl(); - YoungGeneration youngGen = heap.getYoungGeneration(); - OldGeneration oldGen = heap.getOldGeneration(); + private void scanGreyObjects(boolean isIncremental) { Timer scanGreyObjectsTimer = timers.scanGreyObjects.open(); try { - boolean hasGrey; - do { - hasGrey = youngGen.scanGreyObjects(); - hasGrey |= oldGen.scanGreyObjects(); - } while (hasGrey); + if (isIncremental) { + scanGreyObjectsLoop(); + } else { + HeapImpl.getHeapImpl().getOldGeneration().scanGreyObjects(); + } } finally { scanGreyObjectsTimer.close(); } } + private static void scanGreyObjectsLoop() { + HeapImpl heap = HeapImpl.getHeapImpl(); + YoungGeneration youngGen = heap.getYoungGeneration(); + OldGeneration oldGen = heap.getOldGeneration(); + boolean hasGrey; + do { + hasGrey = youngGen.scanGreyObjects(); + hasGrey |= oldGen.scanGreyObjects(); + } while (hasGrey); + } + @AlwaysInline("GC performance") @SuppressWarnings("static-method") Object promoteObject(Object original, UnsignedWord header) { @@ -978,25 +974,23 @@ Object promoteObject(Object original, UnsignedWord header) { } Object result = null; - boolean survivorOverflow = false; - if (originalSpace.getNextAgeForPromotion() < policy.getTenuringAge()) { + if (!completeCollection && originalSpace.getNextAgeForPromotion() < policy.getTenuringAge()) { if (isAligned) { result = heap.getYoungGeneration().promoteAlignedObject(original, (AlignedHeader) originalChunk, originalSpace); } else { result = heap.getYoungGeneration().promoteUnalignedObject(original, (UnalignedHeader) originalChunk, originalSpace); } - survivorOverflow = (result == null); + if (result == null) { + accounting.onSurvivorOverflowed(); + } } - if (result == null) { // tenuring age reached or survivor space full + if (result == null) { // complete collection, tenuring age reached, or survivor space full if (isAligned) { result = heap.getOldGeneration().promoteAlignedObject(original, (AlignedHeader) originalChunk, originalSpace); } else { result = heap.getOldGeneration().promoteUnalignedObject(original, (UnalignedHeader) originalChunk, originalSpace); } assert result != null : "promotion failure in old generation must have been handled"; - if (result != original) { - accounting.onObjectTenured(result, survivorOverflow); - } } return result; @@ -1019,8 +1013,11 @@ private void promotePinnedObject(PinnedObjectImpl pinned) { Space originalSpace = HeapChunk.getSpace(originalChunk); if (originalSpace.isFromSpace()) { boolean promoted = false; - if (originalSpace.getNextAgeForPromotion() < policy.getTenuringAge()) { + if (!completeCollection && originalSpace.getNextAgeForPromotion() < policy.getTenuringAge()) { promoted = heap.getYoungGeneration().promoteChunk(originalChunk, isAligned, originalSpace); + if (!promoted) { + accounting.onSurvivorOverflowed(); + } } if (!promoted) { heap.getOldGeneration().promoteChunk(originalChunk, isAligned, originalSpace); @@ -1175,9 +1172,7 @@ protected void operate(NativeVMOperationData data) { */ ImplicitExceptions.activateImplicitExceptionsAreFatal(); try { - CollectionVMOperationData d = (CollectionVMOperationData) data; - boolean outOfMemory = HeapImpl.getHeapImpl().getGCImpl().collectOperation(GCCause.fromId(d.getCauseId()), d.getRequestingEpoch(), d.getForceFullGC()); - d.setOutOfMemory(outOfMemory); + HeapImpl.getHeapImpl().getGCImpl().collectOperation((CollectionVMOperationData) data); } catch (Throwable t) { throw VMError.shouldNotReachHere(t); } finally { @@ -1206,6 +1201,12 @@ private interface CollectionVMOperationData extends NativeVMOperationData { @RawField void setRequestingEpoch(UnsignedWord value); + @RawField + long getRequestingNanoTime(); + + @RawField + void setRequestingNanoTime(long value); + @RawField boolean getForceFullGC(); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunk.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunk.java index 424e4e2df3b3..0055d2d28982 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunk.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunk.java @@ -288,7 +288,7 @@ public static boolean walkObjectsFromInline(Header that, Pointer startOffset, if (!visitor.visitObjectInline(obj)) { return false; } - offset = offset.add(LayoutEncoding.getSizeFromObject(obj)); + offset = offset.add(LayoutEncoding.getSizeFromObjectInline(obj)); } return true; } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java index 2f887e646ccb..df8cc8897bb4 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java @@ -33,6 +33,7 @@ import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.MemoryWalker; +import com.oracle.svm.core.SubstrateGCOptions; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.annotate.AlwaysInline; import com.oracle.svm.core.annotate.Uninterruptible; @@ -108,7 +109,7 @@ AlignedHeader produceAlignedChunk() { if (result.isNull()) { /* Unused list was empty, need to allocate memory. */ noteFirstAllocationTime(); - result = (AlignedHeader) CommittedMemoryProvider.get().allocate(chunkSize, HeapParameters.getAlignedHeapChunkAlignment(), false); + result = (AlignedHeader) CommittedMemoryProvider.get().allocateAlignedChunk(chunkSize, HeapParameters.getAlignedHeapChunkAlignment()); if (result.isNull()) { throw ALIGNED_OUT_OF_MEMORY_ERROR; } @@ -145,6 +146,10 @@ void consumeAlignedChunks(AlignedHeader firstChunk, boolean keepAll) { } else { UnsignedWord freeListBytes = getBytesInUnusedChunks(); UnsignedWord reserveBytes = GCImpl.getPolicy().getMaximumFreeAlignedChunksSize(); + UnsignedWord maxHeapFree = WordFactory.unsigned(SubstrateGCOptions.MaxHeapFree.getValue()); + if (maxHeapFree.aboveThan(0)) { + reserveBytes = UnsignedUtils.min(reserveBytes, maxHeapFree); + } if (freeListBytes.belowThan(reserveBytes)) { maxChunksToKeep = reserveBytes.subtract(freeListBytes).unsignedDivide(HeapParameters.getAlignedHeapChunkSize()); } else { @@ -262,7 +267,7 @@ UnalignedHeader produceUnalignedChunk(UnsignedWord objectSize) { log().string("[HeapChunkProvider.produceUnalignedChunk objectSize: ").unsigned(objectSize).string(" chunkSize: ").zhex(chunkSize).newline(); noteFirstAllocationTime(); - UnalignedHeader result = (UnalignedHeader) CommittedMemoryProvider.get().allocate(chunkSize, CommittedMemoryProvider.UNALIGNED, false); + UnalignedHeader result = (UnalignedHeader) CommittedMemoryProvider.get().allocateUnalignedChunk(chunkSize); if (result.isNull()) { throw UNALIGNED_OUT_OF_MEMORY_ERROR; } @@ -278,6 +283,10 @@ UnalignedHeader produceUnalignedChunk(UnsignedWord objectSize) { return result; } + public static boolean areUnalignedChunksZeroed() { + return CommittedMemoryProvider.get().areUnalignedChunksZeroed(); + } + /** * Releases a list of UnalignedHeapChunks back to the operating system. They are never recycled * to a free list. @@ -357,12 +366,12 @@ static void freeUnalignedChunkList(UnalignedHeader first) { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) private static void freeAlignedChunk(AlignedHeader chunk) { - CommittedMemoryProvider.get().free(chunk, HeapParameters.getAlignedHeapChunkSize(), HeapParameters.getAlignedHeapChunkAlignment(), false); + CommittedMemoryProvider.get().freeAlignedChunk(chunk, HeapParameters.getAlignedHeapChunkSize(), HeapParameters.getAlignedHeapChunkAlignment()); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) private static void freeUnalignedChunk(UnalignedHeader chunk) { - CommittedMemoryProvider.get().free(chunk, unalignedChunkSize(chunk), CommittedMemoryProvider.UNALIGNED, false); + CommittedMemoryProvider.get().freeUnalignedChunk(chunk, unalignedChunkSize(chunk)); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java index 31803a5b8e61..83cfa91d88d3 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java @@ -30,6 +30,7 @@ import com.oracle.svm.core.SubstrateDiagnostics.DiagnosticThunkRegistry; import com.oracle.svm.core.SubstrateDiagnostics.ErrorContext; +import com.oracle.svm.core.thread.VMThreads.SafepointBehavior; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.core.common.SuppressFBWarnings; @@ -172,6 +173,7 @@ public boolean isInPrimaryImageHeap(Pointer objPointer) { } @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public void suspendAllocation() { ThreadLocalAllocation.suspendInCurrentThread(); } @@ -237,7 +239,7 @@ GCImpl getGCImpl() { @Override @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public boolean isAllocationDisallowed() { - return NoAllocationVerifier.isActive() || gcImpl.isCollectionInProgress(); + return NoAllocationVerifier.isActive() || SafepointBehavior.ignoresSafepoints() || gcImpl.isCollectionInProgress(); } /** A guard to place before an allocation, giving the call site and the allocation type. */ @@ -384,6 +386,7 @@ public void attachThread(IsolateThread isolateThread) { } @Override + @Uninterruptible(reason = "Thread is detaching and holds the THREAD_MUTEX.") public void detachThread(IsolateThread isolateThread) { ThreadLocalAllocation.disableAndFlushForThread(isolateThread); } @@ -638,6 +641,11 @@ public boolean printLocationInfo(Log log, UnsignedWord value, boolean allowJavaH return false; } + @Override + public void updateSizeParameters() { + GCImpl.getPolicy().updateSizeParameters(); + } + static Pointer getImageHeapStart() { int imageHeapOffsetInAddressSpace = Heap.getHeap().getImageHeapOffsetInAddressSpace(); if (imageHeapOffsetInAddressSpace > 0) { @@ -846,7 +854,7 @@ private long totalMemory() { @Substitute private long maxMemory() { PhysicalMemory.size(); // ensure physical memory size is set correctly and not estimated - GCImpl.getPolicy().updateSizeParameters(); + Heap.getHeap().updateSizeParameters(); return GCImpl.getPolicy().getMaximumHeapSize().rawValue(); } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapParameters.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapParameters.java index 145cf91a88eb..d6af7c626da5 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapParameters.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapParameters.java @@ -39,6 +39,7 @@ import com.oracle.svm.core.SubstrateGCOptions; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.Uninterruptible; +import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.option.RuntimeOptionKey; import com.oracle.svm.core.option.RuntimeOptionValues; @@ -48,11 +49,24 @@ /** Constants and variables for the size and layout of the heap and behavior of the collector. */ public final class HeapParameters { public static final class Options { + static final class HeapSizeOptionKey extends RuntimeOptionKey { + HeapSizeOptionKey(T defaultValue) { + super(defaultValue); + } + + @Override + protected void onValueUpdate(EconomicMap, Object> values, T oldValue, T newValue) { + if (!SubstrateUtil.HOSTED) { + Heap.getHeap().updateSizeParameters(); + } + } + } + @Option(help = "The maximum heap size as percent of physical memory") // - public static final RuntimeOptionKey MaximumHeapSizePercent = new RuntimeOptionKey<>(80); + public static final RuntimeOptionKey MaximumHeapSizePercent = new HeapSizeOptionKey<>(80); @Option(help = "The maximum size of the young generation as a percentage of the maximum heap size") // - public static final RuntimeOptionKey MaximumYoungGenerationSizePercent = new RuntimeOptionKey<>(10); + public static final RuntimeOptionKey MaximumYoungGenerationSizePercent = new HeapSizeOptionKey<>(10); @Option(help = "The size of an aligned chunk.") // public static final HostedOptionKey AlignedHeapChunkSize = new HostedOptionKey(1L * 1024L * 1024L) { @@ -99,7 +113,7 @@ public Integer getValue(OptionValues values) { }; @Option(help = "Determines if a full GC collects the young generation separately or together with the old generation.") // - public static final RuntimeOptionKey CollectYoungGenerationSeparately = new RuntimeOptionKey<>(false); + public static final RuntimeOptionKey CollectYoungGenerationSeparately = new RuntimeOptionKey<>(null); private Options() { } @@ -156,6 +170,10 @@ public static void setMinimumHeapSize(UnsignedWord value) { RuntimeOptionValues.singleton().update(SubstrateGCOptions.MinHeapSize, value.rawValue()); } + public static void setMaximumHeapFree(UnsignedWord bytes) { + RuntimeOptionValues.singleton().update(SubstrateGCOptions.MaxHeapFree, bytes.rawValue()); + } + static int getMaximumYoungGenerationSizePercent() { int result = Options.MaximumYoungGenerationSizePercent.getValue(); VMError.guarantee((result >= 0) && (result <= 100), "MaximumYoungGenerationSizePercent should be in [0 ..100]"); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapPolicy.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapPolicy.java deleted file mode 100644 index 6e6f97503b87..000000000000 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapPolicy.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.genscavenge; - -import org.graalvm.compiler.api.replacements.Fold; -import org.graalvm.word.UnsignedWord; - -/** - * Only for compatibility with legacy code, replaced by {@link CollectionPolicy} and - * {@link HeapParameters}. - */ -public final class HeapPolicy { - public static UnsignedWord getMaximumHeapSize() { - return GCImpl.getPolicy().getMaximumHeapSize(); - } - - public static UnsignedWord getMinimumHeapSize() { - return GCImpl.getPolicy().getMinimumHeapSize(); - } - - public static void setMaximumHeapSize(UnsignedWord value) { - HeapParameters.setMaximumHeapSize(value); - } - - public static void setMinimumHeapSize(UnsignedWord value) { - HeapParameters.setMinimumHeapSize(value); - } - - @Fold - public static UnsignedWord getAlignedHeapChunkSize() { - return HeapParameters.getAlignedHeapChunkSize(); - } - - @Fold - public static UnsignedWord getLargeArrayThreshold() { - return HeapParameters.getLargeArrayThreshold(); - } - - private HeapPolicy() { - } -} diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java index 279319c09629..78f8cb73c4a5 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java @@ -361,17 +361,28 @@ private static boolean verifyReference(Object parentObject, Pointer reference, P if (!HeapImpl.getHeapImpl().isInHeap(referencedObject)) { Log.log().string("Object reference at ").zhex(reference).string(" points outside the Java heap: ").zhex(referencedObject).string(". "); - if (parentObject != null) { - Log.log().string("The object that contains the invalid reference is of type ").string(parentObject.getClass().getName()).newline(); - } else { - Log.log().string("The invalid reference is on the stack.").newline(); - } + printParentObject(parentObject); + return false; + } + + if (!ObjectHeaderImpl.getObjectHeaderImpl().pointsToObjectHeader(referencedObject)) { + Log.log().string("Object reference at ").zhex(reference).string(" does not point to a Java object or the object header of the Java object is invalid: ").zhex(referencedObject) + .string(". "); + printParentObject(parentObject); return false; } return true; } + private static void printParentObject(Object parentObject) { + if (parentObject != null) { + Log.log().string("The object that contains the invalid reference is of type ").string(parentObject.getClass().getName()).newline(); + } else { + Log.log().string("The invalid reference is on the stack.").newline(); + } + } + private static class ImageHeapRegionVerifier implements MemoryWalker.ImageHeapRegionVisitor { private final ImageHeapObjectVerifier objectVerifier; diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java index 36fa275c4cb6..a838fab7673d 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.genscavenge; +import com.oracle.svm.core.annotate.AlwaysInline; import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.core.common.CompressEncoding; @@ -327,6 +328,7 @@ static Object getForwardedObject(Pointer ptr, UnsignedWord header) { } /** In an Object, install a forwarding pointer to a different Object. */ + @AlwaysInline("GC performance") static void installForwardingPointer(Object original, Object copy) { assert !isPointerToForwardedObject(Word.objectToUntrackedPointer(original)); UnsignedWord forwardHeader; diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ProportionateSpacesPolicy.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ProportionateSpacesPolicy.java index 76dfc1ecfe7b..261013c9164e 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ProportionateSpacesPolicy.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ProportionateSpacesPolicy.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.core.genscavenge; +import static com.oracle.svm.core.genscavenge.CollectionPolicy.shouldCollectYoungGenSeparately; + import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; @@ -53,7 +55,7 @@ final class ProportionateSpacesPolicy extends AbstractCollectionPolicy { private int shrinkFactor; ProportionateSpacesPolicy() { - super(MAX_TENURING_THRESHOLD); + super(NEW_RATIO, MAX_TENURING_THRESHOLD); } @Override @@ -65,6 +67,11 @@ public String getName() { public boolean shouldCollectCompletely(boolean followingIncrementalCollection) { guaranteeSizeParametersInitialized(); + if (!followingIncrementalCollection && shouldCollectYoungGenSeparately(false)) { + // Note that for non-ParallelGC, HotSpot resets the default of ScavengeBeforeFullGC to + // false, see GCArguments::initialize. + return false; + } if (followingIncrementalCollection && oldSizeExceededInPreviousCollection) { /* * We promoted objects to the old generation beyond its current capacity to avoid a @@ -78,7 +85,7 @@ public boolean shouldCollectCompletely(boolean followingIncrementalCollection) { } @Override - public void onCollectionBegin(boolean completeCollection) { + public void onCollectionBegin(boolean completeCollection, long requestingNanoTime) { } @Override diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java index d47b6d0bd869..35c5d98133c9 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java @@ -27,6 +27,7 @@ import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.VERY_SLOW_PATH_PROBABILITY; import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; +import com.oracle.svm.core.annotate.AlwaysInline; import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -172,25 +173,28 @@ public Log report(Log log, boolean traceHeapChunks) { /** * Allocate memory from an AlignedHeapChunk in this Space. - * - * This is "slow-path" memory allocation. */ + @AlwaysInline("GC performance") private Pointer allocateMemory(UnsignedWord objectSize) { Pointer result = WordFactory.nullPointer(); - /* First try allocating in the last chunk. */ + /* Fast-path: try allocating in the last chunk. */ AlignedHeapChunk.AlignedHeader oldChunk = getLastAlignedHeapChunk(); if (oldChunk.isNonNull()) { result = AlignedHeapChunk.allocateMemory(oldChunk, objectSize); } - /* If oldChunk did not provide, try allocating a new chunk for the requested memory. */ - if (result.isNull()) { - AlignedHeapChunk.AlignedHeader newChunk = requestAlignedHeapChunk(); - if (newChunk.isNonNull()) { - /* Allocate the Object within the new chunk. */ - result = AlignedHeapChunk.allocateMemory(newChunk, objectSize); - } + if (result.isNonNull()) { + return result; } - return result; + /* Slow-path: try allocating a new chunk for the requested memory. */ + return allocateInNewChunk(objectSize); + } + + private Pointer allocateInNewChunk(UnsignedWord objectSize) { + AlignedHeapChunk.AlignedHeader newChunk = requestAlignedHeapChunk(); + if (newChunk.isNonNull()) { + return AlignedHeapChunk.allocateMemory(newChunk, objectSize); + } + return WordFactory.nullPointer(); } public void releaseChunks(ChunkReleaser chunkReleaser) { @@ -352,6 +356,7 @@ private void setLastUnalignedHeapChunk(UnalignedHeapChunk.UnalignedHeader chunk) } /** Promote an aligned Object to this Space. */ + @AlwaysInline("GC performance") Object promoteAlignedObject(Object original, Space originalSpace) { assert ObjectHeaderImpl.isAlignedObject(original); assert this != originalSpace && originalSpace.isFromSpace(); @@ -363,11 +368,12 @@ Object promoteAlignedObject(Object original, Space originalSpace) { return copy; } + @AlwaysInline("GC performance") private Object copyAlignedObject(Object originalObj) { assert VMOperation.isGCInProgress(); assert ObjectHeaderImpl.isAlignedObject(originalObj); - UnsignedWord size = LayoutEncoding.getSizeFromObject(originalObj); + UnsignedWord size = LayoutEncoding.getSizeFromObjectInline(originalObj); Pointer copyMemory = allocateMemory(size); if (probability(VERY_SLOW_PATH_PROBABILITY, copyMemory.isNull())) { return null; diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java index 40219c028e52..1f124f2bbcc9 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java @@ -28,6 +28,7 @@ import static com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets.TLAB_TOP_IDENTITY; import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.replacements.AllocationSnippets.FillContent; import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.Platform; @@ -112,7 +113,8 @@ public interface Descriptor extends PointerBase { * Don't read this value directly, use the {@link Uninterruptible} accessor methods instead. * This is necessary to avoid races between the GC and code that accesses or modifies the TLAB. */ - private static final FastThreadLocalBytes regularTLAB = FastThreadLocalFactory.createBytes(ThreadLocalAllocation::getTlabDescriptorSize).setMaxOffset(FastThreadLocal.BYTE_OFFSET); + private static final FastThreadLocalBytes regularTLAB = FastThreadLocalFactory.createBytes(ThreadLocalAllocation::getTlabDescriptorSize, "ThreadLocalAllocation.regularTLAB") + .setMaxOffset(FastThreadLocal.BYTE_OFFSET); private ThreadLocalAllocation() { } @@ -233,8 +235,9 @@ private static Object slowPathNewArrayWithoutAllocating(DynamicHub hub, int leng if (size.aboveOrEqual(HeapParameters.getLargeArrayThreshold())) { /* Large arrays go into their own unaligned chunk. */ + boolean needsZeroing = !HeapChunkProvider.areUnalignedChunksZeroed(); UnalignedHeapChunk.UnalignedHeader newTlabChunk = HeapImpl.getChunkProvider().produceUnalignedChunk(size); - return allocateLargeArrayInNewTlab(hub, length, size, fillStartOffset, newTlabChunk); + return allocateLargeArrayInNewTlab(hub, length, size, fillStartOffset, newTlabChunk, needsZeroing); } /* Small arrays go into the regular aligned chunk. */ @@ -254,7 +257,7 @@ private static Object slowPathNewArrayWithoutAllocating(DynamicHub hub, int leng @Uninterruptible(reason = "Holds uninitialized memory.") private static Object allocateInstanceInNewTlab(DynamicHub hub, UnsignedWord size, AlignedHeader newTlabChunk) { Pointer memory = allocateRawMemoryInNewTlab(size, newTlabChunk); - return FormatObjectNode.formatObject(memory, DynamicHub.toClass(hub), false, true, true); + return FormatObjectNode.formatObject(memory, DynamicHub.toClass(hub), false, FillContent.WITH_ZEROES, true); } @Uninterruptible(reason = "Holds uninitialized memory.") @@ -263,17 +266,17 @@ private static Object allocateSmallArrayInCurrentTlab(DynamicHub hub, int length return null; } Pointer memory = allocateRawMemoryInTlab(size, getTlab()); - return FormatArrayNode.formatArray(memory, DynamicHub.toClass(hub), length, false, false, true, fillStartOffset, true); + return FormatArrayNode.formatArray(memory, DynamicHub.toClass(hub), length, false, false, FillContent.WITH_ZEROES, fillStartOffset, true); } @Uninterruptible(reason = "Holds uninitialized memory.") private static Object allocateSmallArrayInNewTlab(DynamicHub hub, int length, UnsignedWord size, int fillStartOffset, AlignedHeader newTlabChunk) { Pointer memory = allocateRawMemoryInNewTlab(size, newTlabChunk); - return FormatArrayNode.formatArray(memory, DynamicHub.toClass(hub), length, false, false, true, fillStartOffset, true); + return FormatArrayNode.formatArray(memory, DynamicHub.toClass(hub), length, false, false, FillContent.WITH_ZEROES, fillStartOffset, true); } @Uninterruptible(reason = "Holds uninitialized memory, modifies TLAB") - private static Object allocateLargeArrayInNewTlab(DynamicHub hub, int length, UnsignedWord size, int fillStartOffset, UnalignedHeapChunk.UnalignedHeader newTlabChunk) { + private static Object allocateLargeArrayInNewTlab(DynamicHub hub, int length, UnsignedWord size, int fillStartOffset, UnalignedHeapChunk.UnalignedHeader newTlabChunk, boolean needsZeroing) { ThreadLocalAllocation.Descriptor tlab = getTlab(); HeapChunk.setNext(newTlabChunk, tlab.getUnalignedChunk()); @@ -283,8 +286,13 @@ private static Object allocateLargeArrayInNewTlab(DynamicHub hub, int length, Un Pointer memory = UnalignedHeapChunk.allocateMemory(newTlabChunk, size); assert memory.isNonNull(); - /* Install the DynamicHub and length, and zero the elements. */ - return FormatArrayNode.formatArray(memory, DynamicHub.toClass(hub), length, false, true, true, fillStartOffset, true); + /* + * Install the DynamicHub and length and zero the elements if necessary. If the memory is + * already pre-zeroed, we need to ensure that the snippet code does not fill the memory in + * any way. + */ + FillContent fillKind = needsZeroing ? FillContent.WITH_ZEROES : FillContent.DO_NOT_FILL; + return FormatArrayNode.formatArray(memory, DynamicHub.toClass(hub), length, false, true, fillKind, fillStartOffset, true); } @Uninterruptible(reason = "Returns uninitialized memory, modifies TLAB", callerMustBe = true) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Timers.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Timers.java index dc6c29ae14a2..bd5b1cd255fd 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Timers.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Timers.java @@ -32,7 +32,9 @@ */ final class Timer implements AutoCloseable { private final String name; + private boolean wasOpened; private long openNanos; + private boolean wasClosed; private long closeNanos; private long collectedNanos; @@ -45,29 +47,47 @@ public String getName() { } public Timer open() { - openNanos = System.nanoTime(); + return openAt(System.nanoTime()); + } + + Timer openAt(long nanoTime) { + openNanos = nanoTime; + wasOpened = true; closeNanos = 0L; + wasClosed = false; return this; } @Override public void close() { - /* If a timer was not opened, pretend it was opened at the start of the VM. */ - if (openNanos == 0L) { - openNanos = HeapImpl.getChunkProvider().getFirstAllocationTime(); - } - closeNanos = System.nanoTime(); - collectedNanos += closeNanos - openNanos; + closeAt(System.nanoTime()); + } + + void closeAt(long nanoTime) { + closeNanos = nanoTime; + wasClosed = true; + collectedNanos += closeNanos - getOpenedTime(); } public void reset() { openNanos = 0L; + wasOpened = false; closeNanos = 0L; + wasClosed = false; collectedNanos = 0L; } - public long getFinish() { - assert closeNanos > 0L : "Should have closed timer"; + public long getOpenedTime() { + if (!wasOpened) { + /* If a timer was not opened, pretend it was opened at the start of the VM. */ + assert openNanos == 0; + openNanos = HeapImpl.getChunkProvider().getFirstAllocationTime(); + } + return openNanos; + } + + public long getClosedTime() { + assert wasClosed : "Should have closed timer"; return closeNanos; } @@ -78,9 +98,7 @@ long getMeasuredNanos() { /** Get the nanoseconds collected by the most recent open/close pair. */ long getLastIntervalNanos() { - assert openNanos > 0L : "Should have opened timer"; - assert closeNanos > 0L : "Should have closed timer"; - return closeNanos - openNanos; + return getClosedTime() - getOpenedTime(); } static long getTimeSinceFirstAllocation(long nanos) { @@ -140,8 +158,8 @@ void logAfterCollection(Log log) { if (log.isEnabled()) { log.newline(); log.string(" [GC nanoseconds:"); - logOneTimer(log, " ", verifyBefore); logOneTimer(log, " ", collection); + logOneTimer(log, " ", verifyBefore); logOneTimer(log, " ", rootScan); logOneTimer(log, " ", cheneyScanFromRoots); logOneTimer(log, " ", cheneyScanFromDirtyRoots); @@ -156,7 +174,7 @@ void logAfterCollection(Log log) { logOneTimer(log, " ", cleanCodeCache); logOneTimer(log, " ", referenceObjects); logOneTimer(log, " ", releaseSpaces); - logOneTimer(log, " ", verifyAfter); + logOneTimer(log, " ", verifyAfter); logGCLoad(log, " ", "GCLoad", collection, mutator); log.string("]"); } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/YoungGeneration.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/YoungGeneration.java index bfc13bd95599..209fbad2731d 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/YoungGeneration.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/YoungGeneration.java @@ -151,15 +151,6 @@ void swapSpaces() { assert survivorsToSpacesAccounting.getChunkBytes().equal(0); } - void emptyFromSpacesIntoToSpaces() { - assert getEden().isEmpty() && getEden().getChunkBytes().equal(0) : "Eden must be empty."; - assert survivorsToSpacesAccounting.getChunkBytes().equal(0) : "Survivor to-spaces must be empty"; - for (int i = 0; i < maxSurvivorSpaces; i++) { - assert getSurvivorToSpaceAt(i).isEmpty() && getSurvivorToSpaceAt(i).getChunkBytes().equal(0) : "Survivor to-space must be empty."; - getSurvivorToSpaceAt(i).absorb(getSurvivorFromSpaceAt(i)); - } - } - boolean walkHeapChunks(MemoryWalker.Visitor visitor) { if (getEden().walkHeapChunks(visitor)) { for (int i = 0; i < maxSurvivorSpaces; i++) { diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeAllocationSnippets.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeAllocationSnippets.java index 02c26ff0112b..53f6d2cdeb4a 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeAllocationSnippets.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeAllocationSnippets.java @@ -80,7 +80,7 @@ public static void registerLowering(OptionValues options, Iterable hub, int length, boolean rememberedSet, boolean unaligned, boolean fillContents, int fillStartOffset, boolean emitMemoryBarrier); + public static native Object formatArray(Pointer memory, Class hub, int length, boolean rememberedSet, boolean unaligned, AllocationSnippets.FillContent fillContents, int fillStartOffset, + boolean emitMemoryBarrier); } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/nodes/FormatObjectNode.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/nodes/FormatObjectNode.java index f26e502aa2f2..4af31b952e94 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/nodes/FormatObjectNode.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/nodes/FormatObjectNode.java @@ -33,6 +33,7 @@ import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.replacements.AllocationSnippets.FillContent; import org.graalvm.word.Pointer; @NodeInfo(cycles = CYCLES_64, size = SIZE_64) @@ -75,5 +76,5 @@ public ValueNode getEmitMemoryBarrier() { } @NodeIntrinsic - public static native Object formatObject(Pointer memory, Class hub, boolean rememberedSet, boolean fillContents, boolean emitMemoryBarrier); + public static native Object formatObject(Pointer memory, Class hub, boolean rememberedSet, FillContent fillContents, boolean emitMemoryBarrier); } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/AlignedChunkRememberedSet.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/AlignedChunkRememberedSet.java index 786ee8d82642..902eb59b5dec 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/AlignedChunkRememberedSet.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/AlignedChunkRememberedSet.java @@ -145,7 +145,7 @@ public static void walkDirtyObjects(AlignedHeader chunk, GreyToBlackObjectVisito while (ptr.belowThan(walkLimit)) { Object obj = ptr.toObject(); visitor.visitObjectInline(obj); - ptr = LayoutEncoding.getObjectEnd(obj); + ptr = LayoutEncoding.getObjectEndInline(obj); } } } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTableBasedRememberedSet.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTableBasedRememberedSet.java index 251992239f3e..c9f990d84358 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTableBasedRememberedSet.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTableBasedRememberedSet.java @@ -96,6 +96,7 @@ public void enableRememberedSetForChunk(UnalignedHeader chunk) { } @Override + @AlwaysInline("GC performance") public void enableRememberedSetForObject(AlignedHeader chunk, Object obj) { AlignedChunkRememberedSet.enableRememberedSetForObject(chunk, obj); } @@ -135,12 +136,12 @@ public void dirtyCardIfNecessary(Object holderObject, Object object) { return; } // We dirty the cards of ... - if (HeapParameters.getMaxSurvivorSpaces() != 0 && HeapImpl.getHeapImpl().getYoungGeneration().contains(object)) { + if (HeapParameters.getMaxSurvivorSpaces() != 0 && !GCImpl.getGCImpl().isCompleteCollection() && HeapImpl.getHeapImpl().getYoungGeneration().contains(object)) { /* - * ...references from the old generation to the young generation, unless we do not use - * survivor spaces, in which case there will be no such references because all young - * objects are promoted to the old generation. (We avoid an extra old generation check - * and might remark a few image heap cards, too) + * ...references from the old generation to the young generation, unless there cannot be + * any such references if we do not use survivor spaces, or if we do but are doing a + * complete collection: in both cases, all objects are promoted to the old generation. + * (We avoid an extra old generation check and might remark a few image heap cards, too) */ } else if (HeapImpl.usesImageHeapCardMarking() && GCImpl.getGCImpl().isCompleteCollection() && HeapImpl.getHeapImpl().isInImageHeap(holderObject)) { // ...references from the image heap to the runtime heap, but we clean and remark those diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/FirstObjectTable.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/FirstObjectTable.java index 42130392da61..bfca620613c1 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/FirstObjectTable.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/FirstObjectTable.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.genscavenge.remset; +import com.oracle.svm.core.annotate.AlwaysInline; import org.graalvm.word.Pointer; import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; @@ -177,6 +178,7 @@ private static boolean doInitializeTable(Pointer table, UnsignedWord size) { return true; } + @AlwaysInline("GC performance") public static void setTableForObject(Pointer table, UnsignedWord startOffset, UnsignedWord endOffset) { assert startOffset.belowThan(endOffset); UnsignedWord startIndex = memoryOffsetToIndex(startOffset); @@ -229,6 +231,7 @@ public static void setTableForObject(Pointer table, UnsignedWord startOffset, Un * not at the address of the reference). So, we must skip over the first object if it starts * outside the current card. */ + @AlwaysInline("GC performance") public static Pointer getFirstObjectImprecise(Pointer tableStart, Pointer objectsStart, Pointer objectsLimit, UnsignedWord index) { Pointer result; Pointer firstObject = getFirstObject(tableStart, objectsStart, objectsLimit, index); @@ -246,6 +249,7 @@ public static Pointer getFirstObjectImprecise(Pointer tableStart, Pointer object return result; } + @AlwaysInline("GC performance") private static Pointer getFirstObject(Pointer tableStart, Pointer objectsStart, Pointer objectsLimit, UnsignedWord index) { UnsignedWord currentIndex = index; int currentEntry = getEntryAtIndex(tableStart, currentIndex); diff --git a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64NativeImagePatcher.java b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64NativeImagePatcher.java index 6066e976f68b..cb07b0eadce8 100644 --- a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64NativeImagePatcher.java +++ b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64NativeImagePatcher.java @@ -96,8 +96,9 @@ public int getLength() { } @Override - public void patchCode(int relative, byte[] code) { - annotation.patch(annotation.instructionPosition, relative, code); + public void patchCode(long methodStartAddress, int relative, byte[] code) { + long startAddress = methodStartAddress + annotation.instructionPosition; + annotation.patch(startAddress, relative, code); } @Override @@ -115,8 +116,9 @@ class AdrpLdrMacroInstructionNativeImagePatcher extends CompilationResult.CodeAn } @Override - public void patchCode(int relative, byte[] code) { - macroInstruction.patch(macroInstruction.instructionPosition, relative, code); + public void patchCode(long methodStartAddress, int relative, byte[] code) { + long startAddress = methodStartAddress + macroInstruction.instructionPosition; + macroInstruction.patch(startAddress, relative, code); } @Override @@ -151,8 +153,9 @@ class AdrpAddMacroInstructionNativeImagePatcher extends CompilationResult.CodeAn } @Override - public void patchCode(int relative, byte[] code) { - macroInstruction.patch(macroInstruction.instructionPosition, relative, code); + public void patchCode(long methodStartAddress, int relative, byte[] code) { + long startAddress = methodStartAddress + macroInstruction.instructionPosition; + macroInstruction.patch(startAddress, relative, code); } @Override @@ -187,8 +190,9 @@ class MovSequenceNativeImagePatcher extends CompilationResult.CodeAnnotation imp } @Override - public void patchCode(int relative, byte[] code) { - annotation.patch(annotation.instructionPosition, relative, code); + public void patchCode(long methodStartAddress, int relative, byte[] code) { + long startAddress = methodStartAddress + annotation.instructionPosition; + annotation.patch(startAddress, relative, code); } @Override diff --git a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java index 27dc89fc5e69..6dc8e9d46846 100755 --- a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java +++ b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java @@ -821,10 +821,22 @@ public boolean allowConstantToStackMove(Constant constant) { return super.allowConstantToStackMove(constant); } + private static JavaConstant getZeroConstant(AllocatableValue dst) { + int size = dst.getPlatformKind().getSizeInBytes() * Byte.SIZE; + switch (size) { + case 32: + return JavaConstant.INT_0; + case 64: + return JavaConstant.LONG_0; + default: + throw VMError.shouldNotReachHere(); + } + } + @Override public AArch64LIRInstruction createLoad(AllocatableValue dst, Constant src) { if (CompressedNullConstant.COMPRESSED_NULL.equals(src)) { - return super.createLoad(dst, JavaConstant.INT_0); + return super.createLoad(dst, getZeroConstant(dst)); } else if (src instanceof SubstrateObjectConstant) { return loadObjectConstant(dst, (SubstrateObjectConstant) src); } @@ -834,7 +846,7 @@ public AArch64LIRInstruction createLoad(AllocatableValue dst, Constant src) { @Override public LIRInstruction createStackLoad(AllocatableValue dst, Constant src) { if (CompressedNullConstant.COMPRESSED_NULL.equals(src)) { - return super.createStackLoad(dst, JavaConstant.INT_0); + return super.createStackLoad(dst, getZeroConstant(dst)); } else if (src instanceof SubstrateObjectConstant) { return loadObjectConstant(dst, (SubstrateObjectConstant) src); } @@ -901,7 +913,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.adrpLdr(srcSize, resultReg, resultReg); } if (!constant.isCompressed()) { // the result is expected to be uncompressed - Register baseReg = getBaseRegister(crb); + Register baseReg = getBaseRegister(); assert !baseReg.equals(Register.None) || getShift() != 0 : "no compression in place"; masm.add(64, resultReg, baseReg, resultReg, ShiftType.LSL, getShift()); } diff --git a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64RegisterConfig.java b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64RegisterConfig.java index d8990cb864bf..b39ba697c41c 100755 --- a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64RegisterConfig.java +++ b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64RegisterConfig.java @@ -28,6 +28,7 @@ import static jdk.vm.ci.aarch64.AArch64.allRegisters; import static jdk.vm.ci.aarch64.AArch64.r0; import static jdk.vm.ci.aarch64.AArch64.r1; +import static jdk.vm.ci.aarch64.AArch64.r18; import static jdk.vm.ci.aarch64.AArch64.r19; import static jdk.vm.ci.aarch64.AArch64.r2; import static jdk.vm.ci.aarch64.AArch64.r20; @@ -68,6 +69,7 @@ import java.util.ArrayList; +import com.oracle.svm.core.OS; import com.oracle.svm.core.ReservedRegisters; import com.oracle.svm.core.config.ObjectLayout; import com.oracle.svm.core.graal.code.SubstrateCallingConvention; @@ -138,6 +140,13 @@ public SubstrateAArch64RegisterConfig(ConfigKind config, MetaAccessProvider meta */ regs.remove(ReservedRegisters.singleton().getHeapBaseRegister()); regs.remove(ReservedRegisters.singleton().getThreadRegister()); + /* + * Darwin specifies that r18 is a platform-reserved register: + * https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms + */ + if (OS.getCurrent() == OS.DARWIN) { + regs.remove(r18); + } allocatableRegs = new RegisterArray(regs); switch (config) { diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64NativeImagePatcher.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64NativeImagePatcher.java index 180be26992a8..50fce34fdb47 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64NativeImagePatcher.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64NativeImagePatcher.java @@ -75,7 +75,7 @@ public AMD64NativeImagePatcher(OperandDataAnnotation annotation) { } @Override - public void patchCode(int relative, byte[] code) { + public void patchCode(long methodStartAddress, int relative, byte[] code) { int curValue = relative - (annotation.nextInstructionPosition - annotation.instructionPosition); for (int i = 0; i < annotation.operandSize; i++) { diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java index d0c1672bf8c4..635736397285 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java @@ -901,10 +901,22 @@ public boolean allowConstantToStackMove(Constant constant) { return super.allowConstantToStackMove(constant); } + private static JavaConstant getZeroConstant(AllocatableValue dst) { + int size = dst.getPlatformKind().getSizeInBytes() * Byte.SIZE; + switch (size) { + case 32: + return JavaConstant.INT_0; + case 64: + return JavaConstant.LONG_0; + default: + throw VMError.shouldNotReachHere(); + } + } + @Override public AMD64LIRInstruction createLoad(AllocatableValue dst, Constant src) { if (CompressedNullConstant.COMPRESSED_NULL.equals(src)) { - return super.createLoad(dst, JavaConstant.INT_0); + return super.createLoad(dst, getZeroConstant(dst)); } else if (src instanceof SubstrateObjectConstant) { return loadObjectConstant(dst, (SubstrateObjectConstant) src); } @@ -914,7 +926,7 @@ public AMD64LIRInstruction createLoad(AllocatableValue dst, Constant src) { @Override public LIRInstruction createStackLoad(AllocatableValue dst, Constant src) { if (CompressedNullConstant.COMPRESSED_NULL.equals(src)) { - return super.createStackLoad(dst, JavaConstant.INT_0); + return super.createStackLoad(dst, getZeroConstant(dst)); } else if (src instanceof SubstrateObjectConstant) { return loadObjectConstant(dst, (SubstrateObjectConstant) src); } @@ -983,7 +995,7 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { } } if (!constant.isCompressed()) { // the result is expected to be uncompressed - Register baseReg = getBaseRegister(crb); + Register baseReg = getBaseRegister(); boolean preserveFlagsRegister = true; emitUncompressWithBaseRegister(masm, resultReg, baseReg, getShift(), preserveFlagsRegister); } diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java index c120085082ae..de477e6a83f4 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java @@ -40,9 +40,6 @@ import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere; import static org.graalvm.compiler.debug.GraalError.unimplemented; -// Checkstyle: allow reflection -import java.lang.reflect.Field; -// Checkstyle: disallow reflection import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -63,6 +60,7 @@ import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; import org.graalvm.compiler.core.common.spi.LIRKindTool; +import org.graalvm.compiler.core.common.type.IllegalStamp; import org.graalvm.compiler.core.common.type.RawPointerStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; @@ -130,6 +128,7 @@ import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMBasicBlockRef; import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMTypeRef; import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMValueRef; +import com.oracle.svm.util.ReflectionUtil; import jdk.vm.ci.code.CallingConvention; import jdk.vm.ci.code.CodeCacheProvider; @@ -365,6 +364,9 @@ LLVMTypeRef getLLVMType(Stamp stamp) { if (stamp instanceof RawPointerStamp) { return builder.rawPointerType(); } + if (stamp instanceof IllegalStamp) { + return builder.undefType(); + } return getLLVMType(getTypeKind(stamp.javaType(getMetaAccess()), false), stamp instanceof NarrowOopStamp); } @@ -2011,25 +2013,22 @@ public void emitCacheWritebackSync(boolean isPreSync) { /** * Gets the value of {@code jdk.internal.misc.UnsafeConstants.DATA_CACHE_LINE_FLUSH_SIZE} which - * was introduced in JDK 14 by JEP 352. + * was introduced after JDK 11 by JEP 352. * - * This method uses reflection to be compatible with JDKs prior to 14. + * This method uses reflection to be compatible with JDK 11 and earlier. */ private static int initDataCacheLineFlushSize() { - if (JavaVersionUtil.JAVA_SPEC >= 14) { - Class c; - try { - // Checkstyle: stop - c = Class.forName("jdk.internal.misc.UnsafeConstants"); - // Checkstyle: resume - Field f = c.getDeclaredField("DATA_CACHE_LINE_FLUSH_SIZE"); - f.setAccessible(true); - return (int) f.get(null); - } catch (Exception e) { - throw new GraalError(e, "Expected UnsafeConstants.DATA_CACHE_LINE_FLUSH_SIZE to exist and be readable"); - } + if (JavaVersionUtil.JAVA_SPEC <= 11) { + return 0; + } + try { + // Checkstyle: stop + Class c = Class.forName("jdk.internal.misc.UnsafeConstants"); + // Checkstyle: resume + return ReflectionUtil.readStaticField(c, "DATA_CACHE_LINE_FLUSH_SIZE"); + } catch (ClassNotFoundException e) { + throw new GraalError(e, "Expected UnsafeConstants.DATA_CACHE_LINE_FLUSH_SIZE to exist and be readable"); } - return 0; } private static int getDataCacheLineFlushSize() { diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java index c931cf6b2cc2..e738b8d8ed0f 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java @@ -43,6 +43,7 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; +import com.oracle.svm.shadowed.org.bytedeco.javacpp.Loader; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.debug.DebugContext; @@ -177,8 +178,8 @@ private void compileBitcodeBatches(BatchExecutor executor, DebugContext debug, i stackMapDumper.startDumpingFunctions(); executor.forEach(numBatches, batchId -> (debugContext) -> { - llvmOptimize(debug, getBatchOptimizedFilename(batchId), getBatchBitcodeFilename(batchId)); - llvmCompile(debug, getBatchCompiledFilename(batchId), getBatchOptimizedFilename(batchId)); + //llvmOptimize(debug, getBatchOptimizedFilename(batchId), getBatchBitcodeFilename(batchId)); + llvmCompile(debug, getBatchCompiledFilename(batchId), getBatchBitcodeFilename(batchId)); LLVMStackMapInfo stackMap = objectFileReader.parseStackMap(getBatchCompiledPath(batchId)); IntStream.range(getBatchStart(batchId), getBatchEnd(batchId)).forEach(id -> objectFileReader.readStackMap(stackMap, compilations.get(methodIndex[id]), methodIndex[id], id)); @@ -207,9 +208,10 @@ private void linkCompiledBatches(BatchExecutor executor, DebugContext debug, int stackMapDumper.close(); HostedMethod firstMethod = (HostedMethod) getFirstCompilation().getMethods()[0]; - buildRuntimeMetadata(MethodPointer.factory(firstMethod), WordFactory.signed(textSectionInfo.getCodeSize())); + buildRuntimeMetadata(new MethodPointer(firstMethod), WordFactory.signed(textSectionInfo.getCodeSize())); } + //TODO Optimization currently not supported private void llvmOptimize(DebugContext debug, String outputPath, String inputPath) { List args = new ArrayList<>(); if (LLVMOptions.BitcodeOptimizations.getValue()) { diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/NodeLLVMBuilder.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/NodeLLVMBuilder.java index 8e9a5f4e1936..d37488d46090 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/NodeLLVMBuilder.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/NodeLLVMBuilder.java @@ -27,6 +27,7 @@ import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere; import static org.graalvm.compiler.debug.GraalError.unimplemented; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -35,6 +36,13 @@ import java.util.Map; import java.util.Set; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.ValueKind; +import com.oracle.svm.core.graal.llvm.debug.LLVMDebugInfoBuilder; +import com.oracle.objectfile.debugentry.TypeEntry; +import com.oracle.objectfile.debuginfo.DebugInfoProvider; +import com.oracle.svm.core.graal.llvm.debug.LLVMDebugInfoBuilder; +import com.oracle.svm.core.graal.llvm.debug.LLVMNativeImageDebugInfoProvider; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.core.common.calc.Condition; @@ -129,8 +137,10 @@ public class NodeLLVMBuilder implements NodeLIRBuilderTool, SubstrateNodeLIRBuilder { private final LLVMGenerator gen; private final LLVMIRBuilder builder; - private final RuntimeConfiguration runtimeConfiguration; private final DebugInfoBuilder debugInfoBuilder; + private final LLVMNativeImageDebugInfoProvider debugInfoProvider; + private final RuntimeConfiguration runtimeConfiguration; + public final LLVMDebugInfoBuilder llvmDebugInfoBuilder; private Map valueMap = new HashMap<>(); private final Set> processedBlocks = new HashSet<>(); @@ -140,8 +150,11 @@ public class NodeLLVMBuilder implements NodeLIRBuilderTool, SubstrateNodeLIRBuil protected NodeLLVMBuilder(StructuredGraph graph, LLVMGenerator gen, RuntimeConfiguration runtimeConfiguration) { this.gen = gen; this.builder = gen.getBuilder(); + // TODO The right place for the debuginfobuilder? + this.llvmDebugInfoBuilder = builder.createDIBuilder(graph.method()); this.runtimeConfiguration = runtimeConfiguration; this.debugInfoBuilder = new SubstrateDebugInfoBuilder(graph, gen.getProviders().getMetaAccessExtensionProvider(), this); + this.debugInfoProvider = new LLVMNativeImageDebugInfoProvider(graph.getDebug()); setCompilationResultMethod(gen.getCompilationResult(), graph); for (Block block : graph.getLastSchedule().getCFG().getBlocks()) { @@ -158,7 +171,6 @@ private static void setCompilationResultMethod(CompilationResult result, Structu ResolvedJavaMethod rootMethod = graph.method(); if (rootMethod != null) { result.setMethods(rootMethod, graph.getMethods()); - result.setFields(graph.getFields()); } result.setHasUnsafeAccess(graph.hasUnsafeAccess()); @@ -277,6 +289,25 @@ public void doBlock(Block block, StructuredGraph graph, BlockMap> blo for (Node node : blockMap.get(block)) { if (node instanceof ValueNode) { + DebugInfoProvider.DebugLineInfo debugLineInfo = debugInfoProvider.getLineInfo(node.getNodeSourcePosition()); + if(debugLineInfo != null) { + + int line = debugLineInfo.line(); + if (line != -1){ + /* + *TODO Do this before or after emiting the node? + * */ + llvmDebugInfoBuilder.emitLocation(line); + }else { + //TODO When is this the case + //TODO Temporarly to support inlining for proxies + llvmDebugInfoBuilder.emitLocation(0); + } + }else { + //TODO When is this the case + //TODO Temporarly to support inlining for proxies + llvmDebugInfoBuilder.emitLocation(0); + } /* * There can be cases in which the result of an instruction is already set before by * other instructions. @@ -499,7 +530,6 @@ public void emitInvoke(Invoke i) { LIRFrameState state = state(i); state.initDebugInfo(null, false); DebugInfo debugInfo = state.debugInfo(); - LLVMValueRef callee; boolean isVoid; LLVMValueRef[] args = getCallArguments(arguments, callTarget.callType(), targetMethod); @@ -760,8 +790,14 @@ public Value setResult(ValueNode node, Value operand) { if (operand instanceof LLVMValueWrapper) { llvmOperand = (LLVMValueWrapper) operand; } else if (operand instanceof ConstantValue) { - /* This only happens when emitting null object constants */ - llvmOperand = new LLVMVariable(builder.constantNull(((LLVMKind) operand.getPlatformKind()).get())); + /* This only happens when emitting null or illegal object constants */ + PlatformKind kind = operand.getPlatformKind(); + if (kind instanceof LLVMKind) { + llvmOperand = new LLVMVariable(builder.constantNull(((LLVMKind) kind).get())); + } else { + assert kind == ValueKind.Illegal.getPlatformKind(); + llvmOperand = new LLVMVariable(builder.getUndef()); + } } else if (operand instanceof LLVMAddressValue) { LLVMAddressValue addressValue = (LLVMAddressValue) operand; Value wrappedBase = addressValue.getBase(); diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/SubstrateLLVMBackend.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/SubstrateLLVMBackend.java index c607ed62b74f..0e257a4663c3 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/SubstrateLLVMBackend.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/SubstrateLLVMBackend.java @@ -122,6 +122,7 @@ private void emitLLVM(StructuredGraph graph, CompilationResult result) { /* LLVM generation */ generate(nodeBuilder, graph); + nodeBuilder.llvmDebugInfoBuilder.finalizeBuilder(); byte[] bitcode = generator.getBitcode(); result.setTargetCode(bitcode, bitcode.length); diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/debug/LLVMDebugInfoBuilder.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/debug/LLVMDebugInfoBuilder.java new file mode 100644 index 000000000000..4f424a55cf9a --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/debug/LLVMDebugInfoBuilder.java @@ -0,0 +1,208 @@ +package com.oracle.svm.core.graal.llvm.debug; + +import com.oracle.graal.pointsto.infrastructure.WrappedJavaMethod; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.SubstrateUtil; +import com.oracle.svm.core.graal.llvm.LLVMGenerator; +import com.oracle.svm.core.graal.llvm.util.LLVMIRBuilder; +import com.oracle.svm.core.graal.llvm.util.LLVMOptions; +import com.oracle.svm.core.graal.llvm.util.LLVMUtils; +import com.oracle.svm.hosted.annotation.CustomSubstitutionMethod; +import com.oracle.svm.hosted.annotation.CustomSubstitutionType; +import com.oracle.svm.hosted.image.sources.SourceManager; +import com.oracle.svm.hosted.lambda.LambdaSubstitutionType; +import com.oracle.svm.hosted.meta.HostedField; +import com.oracle.svm.hosted.meta.HostedMethod; +import com.oracle.svm.hosted.meta.HostedType; +import com.oracle.svm.hosted.substitute.InjectedFieldsType; +import com.oracle.svm.hosted.substitute.SubstitutionMethod; +import com.oracle.svm.hosted.substitute.SubstitutionType; +import com.oracle.svm.shadowed.org.bytedeco.javacpp.PointerPointer; +import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMAttributeRef; +import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMBuilderRef; +import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMContextRef; +import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMDIBuilderRef; +import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMMetadataRef; +import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMModuleRef; +import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMTypeRef; +import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMValueMetadataEntry; +import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMValueRef; +import com.oracle.svm.shadowed.org.bytedeco.llvm.global.LLVM; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.graph.NodeSourcePosition; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.nativeimage.ImageSingletons; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class LLVMDebugInfoBuilder { + + private LLVMContextRef context; + private LLVMDIBuilderRef diBuilder; + private LLVMBuilderRef builder; + + private LLVMMetadataRef cu; + private LLVMMetadataRef file; + private LLVMMetadataRef subprogram; + //private LLVMMetadataRef scope;//TODO Cu should need? + private ResolvedJavaMethod method; + private Path path; + + public LLVMDebugInfoBuilder(DebugContext debugContext, ResolvedJavaMethod method, LLVMContextRef context, LLVMModuleRef moduleRef, LLVMBuilderRef builderRef){ + this.context = context; + this.method = method; + this.builder = builderRef; + + ResolvedJavaType javaType = getDeclaringClass((HostedMethod) method, false); + HostedType hostedType = ((HostedMethod) method).getDeclaringClass(); + Class clazz = hostedType.getJavaClass(); + SourceManager sourceManager = ImageSingletons.lookup(SourceManager.class); + path = sourceManager.findAndCacheSource(javaType, clazz, debugContext); + + diBuilder = LLVM.LLVMCreateDIBuilder(moduleRef); + + if (path == null) { + //TODO could also happen when not defining -H:DebugInfoSourceSearchPath. Should be handled better + //TODO This seems to be the case for Proxys + // TODO At first just emit dummy files + file = LLVM.LLVMDIBuilderCreateFile(diBuilder, (String) null, 0, null, 0); + //return; + } else { + path = Paths.get(SubstrateOptions.DebugInfoSourceCacheRoot.getValue(), path.toString()); + file = LLVM.LLVMDIBuilderCreateFile(diBuilder, path.getFileName().toString(), path.getFileName().toString().length(), path.getParent().toAbsolutePath().toString(), path.getParent().toAbsolutePath().toString().length()); + } + + cu = LLVM.LLVMDIBuilderCreateCompileUnit(diBuilder, + LLVM.LLVMDWARFSourceLanguageJava, + file, + "LLVM version 12.0.1-3-g6e0a5672bc-bgf11ed69a5a", + "LLVM version 12.0.1-3-g6e0a5672bc-bgf11ed69a5a".length(), + 0, + null, + 0, + 3, + null, + 0, + LLVM.LLVMDWARFEmissionFull, + 0, + 0, + 0, + null, + 0, + null, + 0); + LLVM.LLVMAddModuleFlag(moduleRef, LLVM.LLVMModuleFlagBehaviorOverride, "Dwarf Version", "Dwarf Version".length(), LLVM.LLVMValueAsMetadata(LLVM.LLVMConstInt(LLVM.LLVMInt32TypeInContext(context), 4, 0))); + LLVM.LLVMAddModuleFlag(moduleRef, LLVM.LLVMModuleFlagBehaviorOverride, "Debug Info Version", "Debug Info Version".length(), LLVM.LLVMValueAsMetadata(LLVM.LLVMConstInt(LLVM.LLVMInt32TypeInContext(context), 3, 0))); + LLVMValueRef functionRef = LLVM.LLVMGetNamedFunction(moduleRef, SubstrateUtil.uniqueShortName(method)); + + // TODO: 15.11.2021 We need to also emit debug info for proxies, when no source code is available + int line = 0; + if (method.getLineNumberTable() != null) { + //TODO What das this case mean? + line = method.getLineNumberTable().getLineNumbers()[0]; + //return; + } + + /*LLVM.LLVMDIBuilderCreateParameterVariable(diBuilder, + cu,//TODO Correct scope? + );*/ + //TODO Parametertypes needs to be defined + LLVMMetadataRef subRoutineType = LLVM.LLVMDIBuilderCreateSubroutineType(diBuilder, file, (LLVMMetadataRef) null, 0, 0); + subprogram = LLVM.LLVMDIBuilderCreateFunction(diBuilder, + cu, + name(),// Maybe better a combination of Class name and method name better + name().length(), + SubstrateUtil.uniqueShortName(method), + SubstrateUtil.uniqueShortName(method).length(), + file, + line, + subRoutineType, + 1, + 1, + 0, + 0, + 0); + LLVM.LLVMSetSubprogram(functionRef, subprogram); + } + + public void emitLocation(int line) { + if (subprogram == null) { + //Currently wont happen + //TODO When the lineNumberTable was empty + return; + } + LLVM.LLVMSetCurrentDebugLocation2(builder, LLVM.LLVMDIBuilderCreateDebugLocation(context, line, 0, subprogram, null)); + } + + public void finalizeBuilder() { + LLVM.LLVMDIBuilderFinalize(diBuilder); + LLVM.LLVMDisposeDIBuilder(diBuilder); + } + + /* + * TODO Copied from NativeImageDebugInfoProvider + */ + public String name() { + ResolvedJavaMethod targetMethod = method; + while (targetMethod instanceof WrappedJavaMethod) { + targetMethod = ((WrappedJavaMethod) targetMethod).getWrapped(); + } + if (targetMethod instanceof SubstitutionMethod) { + targetMethod = ((SubstitutionMethod) targetMethod).getOriginal(); + } else if (targetMethod instanceof CustomSubstitutionMethod) { + targetMethod = ((CustomSubstitutionMethod) targetMethod).getOriginal(); + } + String name = targetMethod.getName(); + if (name.equals("")) { + if (method instanceof HostedMethod) { + name = getDeclaringClass((HostedMethod) method, true).toJavaName(); + if (name.indexOf('.') >= 0) { + name = name.substring(name.lastIndexOf('.') + 1); + } + if (name.indexOf('$') >= 0) { + name = name.substring(name.lastIndexOf('$') + 1); + } + } else { + name = targetMethod.format("%h"); + if (name.indexOf('$') >= 0) { + name = name.substring(name.lastIndexOf('$') + 1); + } + } + } + return name; + } + + protected static ResolvedJavaType getDeclaringClass(HostedMethod hostedMethod, boolean wantOriginal) { + if (wantOriginal) { + return getOriginal(hostedMethod.getDeclaringClass()); + } + // we want a substituted target if there is one. if there is a substitution at the end of + // the method chain fetch the annotated target class + ResolvedJavaMethod javaMethod = hostedMethod.getWrapped().getWrapped(); + if (javaMethod instanceof SubstitutionMethod) { + SubstitutionMethod substitutionMethod = (SubstitutionMethod) javaMethod; + return substitutionMethod.getAnnotated().getDeclaringClass(); + } + return javaMethod.getDeclaringClass(); + } + + private static ResolvedJavaType getOriginal(HostedType hostedType) { + /* partially unwrap then traverse through substitutions to the original */ + ResolvedJavaType javaType = hostedType.getWrapped().getWrappedWithoutResolve(); + if (javaType instanceof SubstitutionType) { + return ((SubstitutionType) javaType).getOriginal(); + } else if (javaType instanceof CustomSubstitutionType) { + return ((CustomSubstitutionType) javaType).getOriginal(); + } else if (javaType instanceof LambdaSubstitutionType) { + return ((LambdaSubstitutionType) javaType).getOriginal(); + } else if (javaType instanceof InjectedFieldsType) { + return ((InjectedFieldsType) javaType).getOriginal(); + } + return javaType; + } +} + diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/debug/LLVMNativeImageDebugInfoProvider.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/debug/LLVMNativeImageDebugInfoProvider.java new file mode 100644 index 000000000000..27a21d88685c --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/debug/LLVMNativeImageDebugInfoProvider.java @@ -0,0 +1,218 @@ +package com.oracle.svm.core.graal.llvm.debug; + +import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; +import com.oracle.graal.pointsto.infrastructure.WrappedJavaMethod; +import com.oracle.objectfile.debuginfo.DebugInfoProvider; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.hosted.annotation.CustomSubstitutionMethod; +import com.oracle.svm.hosted.image.NativeImage; +import com.oracle.svm.hosted.image.sources.SourceManager; +import com.oracle.svm.hosted.meta.HostedMethod; +import com.oracle.svm.hosted.substitute.SubstitutionMethod; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.LineNumberTable; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.Signature; +import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.NodeSourcePosition; +import org.graalvm.nativeimage.ImageSingletons; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import static com.oracle.svm.hosted.image.NativeImageDebugInfoProvider.getDeclaringClass; +import static com.oracle.svm.hosted.image.NativeImageDebugInfoProvider.toJavaName; + +/** + * Incomplete and currently not really used implementation of NativeImageDebugInfoProvider. Will be probably used more later. + * Implemented by Noisyfox + * */ +public class LLVMNativeImageDebugInfoProvider { + private final DebugContext debugContext; + + public LLVMNativeImageDebugInfoProvider(DebugContext debugContext) { + this.debugContext = debugContext; + } + + public DebugInfoProvider.DebugLineInfo getLineInfo(NodeSourcePosition position) { + if (position == null) { + return null; + } + + return new LLVMNativeImageDebugLineInfo(position); + } + + class LLVMNativeImageDebugLineInfo implements DebugInfoProvider.DebugLineInfo { + + private final int bci; + private final ResolvedJavaMethod method; + private final Path cachePath; + private Path fullFilePath; + + public LLVMNativeImageDebugLineInfo(NodeSourcePosition position) { + int posbci = position.getBCI(); + this.bci = (posbci >= 0 ? posbci : 0); + method = position.getMethod(); + this.cachePath = SubstrateOptions.getDebugInfoSourceCacheRoot(); + computeFullFilePath(); + } + + @Override + public String fileName() { + if (fullFilePath != null) { + Path fileName = fullFilePath.getFileName(); + if (fileName != null) { + return fileName.toString(); + } + } + return null; + } + + @Override + public Path filePath() { + if (fullFilePath != null) { + return fullFilePath.getParent(); + } + return null; + } + + @Override + public Path cachePath() { + return cachePath; + } + + @Override + public ResolvedJavaType ownerType() { + if (method instanceof HostedMethod) { + return getDeclaringClass((HostedMethod) method, true); + } + return method.getDeclaringClass(); + } + + @Override + public String name() { + ResolvedJavaMethod targetMethod = method; + while (targetMethod instanceof WrappedJavaMethod) { + targetMethod = ((WrappedJavaMethod) targetMethod).getWrapped(); + } + if (targetMethod instanceof SubstitutionMethod) { + targetMethod = ((SubstitutionMethod) targetMethod).getOriginal(); + } else if (targetMethod instanceof CustomSubstitutionMethod) { + targetMethod = ((CustomSubstitutionMethod) targetMethod).getOriginal(); + } + String name = targetMethod.getName(); + if (name.equals("")) { + if (method instanceof HostedMethod) { + name = getDeclaringClass((HostedMethod) method, true).toJavaName(); + if (name.indexOf('.') >= 0) { + name = name.substring(name.lastIndexOf('.') + 1); + } + if (name.indexOf('$') >= 0) { + name = name.substring(name.lastIndexOf('$') + 1); + } + } else { + name = targetMethod.format("%h"); + if (name.indexOf('$') >= 0) { + name = name.substring(name.lastIndexOf('$') + 1); + } + } + } + return name; + } + + @Override + public String valueType() { + return method.format("%R"); + } + + @Override + public int modifiers() { + return method.getModifiers(); + } + + @Override + public List paramTypes() { + Signature signature = method.getSignature(); + int parameterCount = signature.getParameterCount(false); + List paramTypes = new ArrayList<>(parameterCount); + for (int i = 0; i < parameterCount; i++) { + JavaType parameterType = signature.getParameterType(i, null); + paramTypes.add(toJavaName(parameterType)); + } + return paramTypes; + } + + @Override + public List paramNames() { + /* Can only provide blank names for now. */ + Signature signature = method.getSignature(); + int parameterCount = signature.getParameterCount(false); + List paramNames = new ArrayList<>(parameterCount); + for (int i = 0; i < parameterCount; i++) { + paramNames.add(""); + } + return paramNames; + } + + @Override + public String symbolNameForMethod() { + return NativeImage.localSymbolNameForMethod(method); + } + + @Override + public boolean isDeoptTarget() { + if (method instanceof HostedMethod) { + return ((HostedMethod) method).isDeoptTarget(); + } + return name().endsWith(HostedMethod.METHOD_NAME_DEOPT_SUFFIX); + } + + @Override + public int addressLo() { + throw GraalError.unimplemented(); + } + + @Override + public int addressHi() { + throw GraalError.unimplemented(); + } + + @Override + public int line() { + LineNumberTable lineNumberTable = method.getLineNumberTable(); + if (lineNumberTable != null) { + return lineNumberTable.getLineNumber(bci); + } + return -1; + } + + @Override + public DebugInfoProvider.DebugLineInfo getCaller() { + throw GraalError.unimplemented(); + } + + private void computeFullFilePath() { + ResolvedJavaType declaringClass; + // if we have a HostedMethod then deal with substitutions + if (method instanceof HostedMethod) { + declaringClass = getDeclaringClass((HostedMethod) method, false); + } else { + declaringClass = method.getDeclaringClass(); + } + Class clazz = null; + if (declaringClass instanceof OriginalClassProvider) { + clazz = ((OriginalClassProvider) declaringClass).getJavaClass(); + } + SourceManager sourceManager = ImageSingletons.lookup(SourceManager.class); + try (DebugContext.Scope s = debugContext.scope("DebugCodeInfo", declaringClass)) { + fullFilePath = sourceManager.findAndCacheSource(declaringClass, clazz, debugContext); + } catch (Throwable e) { + throw debugContext.handle(e); + } + } + } + +} diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/lowering/LLVMLoadExceptionObjectLowering.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/lowering/LLVMLoadExceptionObjectLowering.java index 5f37e72d6f15..091091ab13a4 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/lowering/LLVMLoadExceptionObjectLowering.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/lowering/LLVMLoadExceptionObjectLowering.java @@ -25,13 +25,13 @@ package com.oracle.svm.core.graal.llvm.lowering; import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.java.LoadExceptionObjectNode; import org.graalvm.compiler.nodes.spi.LoweringTool; -import com.oracle.svm.core.graal.nodes.ExceptionStateNode; import com.oracle.svm.core.graal.nodes.ReadExceptionObjectNode; import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; import com.oracle.svm.core.nodes.CFunctionEpilogueNode; @@ -42,9 +42,10 @@ public class LLVMLoadExceptionObjectLowering implements NodeLoweringProvider getPackagesDefinedToLoader(ClassLoader loader) { return getDefinedModules().getOrDefault(loader, Set.of()) - .stream() - .flatMap(m -> m.getPackages().stream()) - .collect(Collectors.toUnmodifiableList()); + .stream() + .flatMap(m -> m.getPackages().stream()) + .collect(Collectors.toUnmodifiableList()); } public static Object getModuleContainingPackage(ClassLoader loader, String pn) { return getDefinedModules().getOrDefault(loader, Set.of()) - .stream() - .filter(m -> m.getPackages().contains(pn)) - .findFirst().orElse(null); + .stream() + .filter(m -> m.getPackages().contains(pn)) + .findFirst().orElse(null); } public static boolean bootLayerContainsModule(String name) { return ModuleLayer.boot().modules().stream().anyMatch(m -> m.getName().equals(name)); } - //Checkstyle: allow synchronization + // Checkstyle: allow synchronization public static void defineModule(Module module, boolean isOpen, List pns) { if (Objects.isNull(module)) { throw new NullPointerException("Null module object"); @@ -178,7 +178,7 @@ public static void defineModule(Module module, boolean isOpen, List pns) if (loader != ClassLoader.getPlatformClassLoader() && ModuleUtil.isPackageNameForbidden(pn)) { throw new IllegalArgumentException("Class loader (instance of): " + loader.getClass().getName() + - " tried to define prohibited package name: " + pn); + " tried to define prohibited package name: " + pn); } } @@ -202,11 +202,9 @@ public static void defineModule(Module module, boolean isOpen, List pns) } else if (Objects.nonNull(definedPackage)) { Module moduleContainingDefinedPackage = SubstrateUtil.cast(ModuleUtil.getModuleContainingPackage(loader, definedPackage), Module.class); if (moduleContainingDefinedPackage.isNamed()) { - throw new IllegalStateException("Package " + definedPackage + " is already in another module, " - + moduleContainingDefinedPackage.getName() + ", defined to the class loader"); + throw new IllegalStateException("Package " + definedPackage + " is already in another module, " + moduleContainingDefinedPackage.getName() + ", defined to the class loader"); } else { - throw new IllegalStateException("Package " + definedPackage - + " is already in the unnamed module defined to the class loader"); + throw new IllegalStateException("Package " + definedPackage + " is already in the unnamed module defined to the class loader"); } } diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_ClassLoader_JDK11OrLater.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_ClassLoader_JDK11OrLater.java index 335d7feedad6..33b5b3c8cfd1 100644 --- a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_ClassLoader_JDK11OrLater.java +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_ClassLoader_JDK11OrLater.java @@ -41,11 +41,10 @@ public final class Target_java_lang_ClassLoader_JDK11OrLater { /** * All ClassLoaderValue are reset at run time for now. See also - * {@link Target_jdk_internal_loader_BootLoader_JDK11OrLater#CLASS_LOADER_VALUE_MAP} for resetting of the - * boot class loader. + * {@link Target_jdk_internal_loader_BootLoader_JDK11OrLater#CLASS_LOADER_VALUE_MAP} for + * resetting of the boot class loader. */ - @Alias - @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.NewInstance, declClass = ConcurrentHashMap.class)// + @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.NewInstance, declClass = ConcurrentHashMap.class)// @TargetElement(onlyWith = JDK11OrLater.class)// ConcurrentHashMap classLoaderValueMap; @@ -53,6 +52,7 @@ public final class Target_java_lang_ClassLoader_JDK11OrLater { @TargetElement(onlyWith = JDK11OrLater.class) native Stream packages(); + @SuppressWarnings("static-method") @Substitute public Target_java_lang_Module_JDK11OrLater getUnnamedModule() { return ClassLoaderUtil.unnamedModuleReference.get(); diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_Module_JDK11OrLater.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_Module_JDK11OrLater.java index 53b5b2217105..a77695ddac3f 100644 --- a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_Module_JDK11OrLater.java +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_Module_JDK11OrLater.java @@ -24,21 +24,21 @@ */ package com.oracle.svm.core.jdk11; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Objects; + import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.annotate.TargetElement; +import com.oracle.svm.core.jdk.JDK11OrEarlier; import com.oracle.svm.core.jdk.JDK11OrLater; -import com.oracle.svm.core.jdk.JDK11To14; import com.oracle.svm.core.jdk.Resources; import com.oracle.svm.core.jdk.resources.ResourceStorageEntry; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.util.Arrays; -import java.util.Objects; - @SuppressWarnings("unused") @TargetClass(value = java.lang.Module.class, onlyWith = JDK11OrLater.class) public final class Target_java_lang_Module_JDK11OrLater { @@ -58,7 +58,7 @@ public InputStream getResourceAsStream(String name) { } @Substitute // - @TargetElement(onlyWith = JDK11To14.class) + @TargetElement(onlyWith = {JDK11OrLater.class, JDK11OrEarlier.class}) private static void defineModule0(Module module, boolean isOpen, String version, String location, String[] pns) { ModuleUtil.defineModule(module, isOpen, Arrays.asList(pns)); } diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/substitutions/Target_java_util_ResourceBundle.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/localization/substitutions/Target_java_util_ResourceBundle.java similarity index 88% rename from substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/substitutions/Target_java_util_ResourceBundle.java rename to substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/localization/substitutions/Target_java_util_ResourceBundle.java index 7c5f36d0acd3..a6b5f95b2b17 100644 --- a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/substitutions/Target_java_util_ResourceBundle.java +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/localization/substitutions/Target_java_util_ResourceBundle.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk11.substitutions; +package com.oracle.svm.core.jdk11.localization.substitutions; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; @@ -44,12 +44,12 @@ public final class Target_java_util_ResourceBundle { */ @Substitute - private static ResourceBundle getBundle(String baseName, Target_java_lang_Module_JDK11OrLater module) { + private static ResourceBundle getBundle(String baseName, @SuppressWarnings("unused") Target_java_lang_Module_JDK11OrLater module) { return ImageSingletons.lookup(LocalizationSupport.class).asOptimizedSupport().getCached(baseName, Locale.getDefault()); } @Substitute - private static ResourceBundle getBundle(String baseName, Locale targetLocale, Target_java_lang_Module_JDK11OrLater module) { + private static ResourceBundle getBundle(String baseName, Locale targetLocale, @SuppressWarnings("unused") Target_java_lang_Module_JDK11OrLater module) { return ImageSingletons.lookup(LocalizationSupport.class).asOptimizedSupport().getCached(baseName, targetLocale); } } diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/localization/Target_sun_util_resources_Bundles.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/localization/substitutions/Target_sun_util_resources_Bundles.java similarity index 97% rename from substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/localization/Target_sun_util_resources_Bundles.java rename to substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/localization/substitutions/Target_sun_util_resources_Bundles.java index e51e8a004f10..a30c9a5b4524 100644 --- a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/localization/Target_sun_util_resources_Bundles.java +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/localization/substitutions/Target_sun_util_resources_Bundles.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk11.localization; +package com.oracle.svm.core.jdk11.localization.substitutions; import java.util.Locale; import java.util.ResourceBundle; diff --git a/substratevm/src/com.oracle.svm.core.jdk15/src/com/oracle/svm/core/jdk15/HiddenClassSupportImpl.java b/substratevm/src/com.oracle.svm.core.jdk15/src/com/oracle/svm/core/jdk15/HiddenClassSupportImpl.java deleted file mode 100644 index a8981b0cfd79..000000000000 --- a/substratevm/src/com.oracle.svm.core.jdk15/src/com/oracle/svm/core/jdk15/HiddenClassSupportImpl.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.jdk15; - -import org.graalvm.compiler.serviceprovider.JavaVersionUtil; -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.hosted.Feature; - -import com.oracle.svm.core.annotate.AutomaticFeature; -import com.oracle.svm.core.jdk.HiddenClassSupport; - -final class HiddenClassSupportImpl extends HiddenClassSupport { - @Override - public boolean isHidden(Class clazz) { - return clazz.isHidden(); - } -} - -@AutomaticFeature -final class HiddenClassFeature implements Feature { - @Override - public boolean isInConfiguration(IsInConfigurationAccess access) { - return JavaVersionUtil.JAVA_SPEC >= 15; - } - - @Override - public void afterRegistration(AfterRegistrationAccess access) { - ImageSingletons.add(HiddenClassSupport.class, new HiddenClassSupportImpl()); - } -} diff --git a/substratevm/src/com.oracle.svm.core.jdk16/src/com/oracle/svm/core/jdk16/JDKClassLoadingDeadlockWorkaround.java b/substratevm/src/com.oracle.svm.core.jdk16/src/com/oracle/svm/core/jdk16/JDKClassLoadingDeadlockWorkaround.java deleted file mode 100644 index 70fdf9871f68..000000000000 --- a/substratevm/src/com.oracle.svm.core.jdk16/src/com/oracle/svm/core/jdk16/JDKClassLoadingDeadlockWorkaround.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.jdk16; - -import java.lang.constant.ConstantDescs; - -import org.graalvm.compiler.serviceprovider.JavaVersionUtil; -import org.graalvm.nativeimage.hosted.Feature; - -import com.oracle.svm.core.annotate.AutomaticFeature; - -/** - * Workaround for JDK bug JDK-8263108. Class initialization of classes in java.lang.constant can - * deadlock during the multi-threaded static analysis. Forcing class initialization early before the - * analysis resolves the problem. - */ -@AutomaticFeature -final class JDKClassLoadingDeadlockWorkaround implements Feature { - @Override - public boolean isInConfiguration(IsInConfigurationAccess access) { - return JavaVersionUtil.JAVA_SPEC >= 16; - } - - @SuppressWarnings("unused") - @Override - public void afterRegistration(AfterRegistrationAccess access) { - Object unused = ConstantDescs.CD_Object; - } -} diff --git a/substratevm/src/com.oracle.svm.core.jdk16/src/com/oracle/svm/core/jdk16/RecordSupportJDK16OrLater.java b/substratevm/src/com.oracle.svm.core.jdk17/src/com/oracle/svm/core/jdk17/RecordSupportJDK17OrLater.java similarity index 93% rename from substratevm/src/com.oracle.svm.core.jdk16/src/com/oracle/svm/core/jdk16/RecordSupportJDK16OrLater.java rename to substratevm/src/com.oracle.svm.core.jdk17/src/com/oracle/svm/core/jdk17/RecordSupportJDK17OrLater.java index 70e543c7697a..4a38a60ba77e 100644 --- a/substratevm/src/com.oracle.svm.core.jdk16/src/com/oracle/svm/core/jdk16/RecordSupportJDK16OrLater.java +++ b/substratevm/src/com.oracle.svm.core.jdk17/src/com/oracle/svm/core/jdk17/RecordSupportJDK17OrLater.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk16; +package com.oracle.svm.core.jdk17; // Checkstyle: allow reflection @@ -39,7 +39,7 @@ import com.oracle.svm.core.jdk.RecordSupport; import com.oracle.svm.core.util.VMError; -final class RecordSupportJDK16OrLater extends RecordSupport { +final class RecordSupportJDK17OrLater extends RecordSupport { @Override public boolean isRecord(Class clazz) { return clazz.isRecord(); @@ -73,14 +73,14 @@ public Constructor getCanonicalRecordConstructor(Class clazz) { } @AutomaticFeature -final class RecordFeatureJDK16OrLater implements Feature { +final class RecordFeatureJDK17OrLater implements Feature { @Override public boolean isInConfiguration(IsInConfigurationAccess access) { - return JavaVersionUtil.JAVA_SPEC >= 16; + return JavaVersionUtil.JAVA_SPEC >= 17; } @Override public void afterRegistration(AfterRegistrationAccess access) { - ImageSingletons.add(RecordSupport.class, new RecordSupportJDK16OrLater()); + ImageSingletons.add(RecordSupport.class, new RecordSupportJDK17OrLater()); } } diff --git a/substratevm/src/com.oracle.svm.core.jdk15/src/com/oracle/svm/core/jdk15/Target_java_lang_ClassLoader_JDK15OrLater.java b/substratevm/src/com.oracle.svm.core.jdk17/src/com/oracle/svm/core/jdk17/Target_java_lang_ClassLoader_JDK17OrLater.java similarity index 87% rename from substratevm/src/com.oracle.svm.core.jdk15/src/com/oracle/svm/core/jdk15/Target_java_lang_ClassLoader_JDK15OrLater.java rename to substratevm/src/com.oracle.svm.core.jdk17/src/com/oracle/svm/core/jdk17/Target_java_lang_ClassLoader_JDK17OrLater.java index d3cf2247687a..414a31e47c77 100644 --- a/substratevm/src/com.oracle.svm.core.jdk15/src/com/oracle/svm/core/jdk15/Target_java_lang_ClassLoader_JDK15OrLater.java +++ b/substratevm/src/com.oracle.svm.core.jdk17/src/com/oracle/svm/core/jdk17/Target_java_lang_ClassLoader_JDK17OrLater.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk15; +package com.oracle.svm.core.jdk17; import java.io.File; import java.util.Deque; @@ -32,15 +32,15 @@ import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; -import com.oracle.svm.core.jdk.JDK15OrLater; +import com.oracle.svm.core.jdk.JDK17OrLater; import com.oracle.svm.core.jdk.NativeLibrarySupport; import jdk.internal.loader.NativeLibraries; import jdk.internal.loader.NativeLibrary; -@TargetClass(value = ClassLoader.class, onlyWith = JDK15OrLater.class) +@TargetClass(value = ClassLoader.class, onlyWith = JDK17OrLater.class) @SuppressWarnings({"static-method", "unused"}) -final class Target_java_lang_ClassLoader_JDK15OrLater { +final class Target_java_lang_ClassLoader_JDK17OrLater { @Substitute static NativeLibrary loadLibrary(Class fromClass, String name) { @@ -57,8 +57,8 @@ static NativeLibrary loadLibrary(Class fromClass, File file) { } } -@TargetClass(value = jdk.internal.loader.NativeLibraries.class, onlyWith = JDK15OrLater.class) -final class Target_jdk_internal_loader_NativeLibraries_JDK15OrLater { +@TargetClass(value = jdk.internal.loader.NativeLibraries.class, onlyWith = JDK17OrLater.class) +final class Target_jdk_internal_loader_NativeLibraries_JDK17OrLater { /** * The NativeLibraries is only used by the `loadLibrary` methods that are substituted, so we do @@ -88,7 +88,7 @@ public static NativeLibraries jniNativeLibraries(ClassLoader loader) { */ @Delete - private static native boolean load(Target_jdk_internal_loader_NativeLibraries_NativeLibraryImpl_JDK15OrLater impl, String name, boolean isBuiltin, boolean isJNI); + private static native boolean load(Target_jdk_internal_loader_NativeLibraries_NativeLibraryImpl_JDK17OrLater impl, String name, boolean isBuiltin, boolean isJNI); @Delete private static native void unload(String name, boolean isBuiltin, boolean isJNI, long handle); @@ -97,9 +97,9 @@ public static NativeLibraries jniNativeLibraries(ClassLoader loader) { private static native String findBuiltinLib(String name); @Delete - private static native long findEntry0(Target_jdk_internal_loader_NativeLibraries_NativeLibraryImpl_JDK15OrLater lib, String name); + private static native long findEntry0(Target_jdk_internal_loader_NativeLibraries_NativeLibraryImpl_JDK17OrLater lib, String name); } -@TargetClass(value = jdk.internal.loader.NativeLibraries.class, innerClass = "NativeLibraryImpl", onlyWith = JDK15OrLater.class) -final class Target_jdk_internal_loader_NativeLibraries_NativeLibraryImpl_JDK15OrLater { +@TargetClass(value = jdk.internal.loader.NativeLibraries.class, innerClass = "NativeLibraryImpl", onlyWith = JDK17OrLater.class) +final class Target_jdk_internal_loader_NativeLibraries_NativeLibraryImpl_JDK17OrLater { } diff --git a/substratevm/src/com.oracle.svm.core.jdk15/src/com/oracle/svm/core/jdk15/Target_java_lang_Module_JDK15OrLater.java b/substratevm/src/com.oracle.svm.core.jdk17/src/com/oracle/svm/core/jdk17/Target_java_lang_Module_JDK17OrLater.java similarity index 88% rename from substratevm/src/com.oracle.svm.core.jdk15/src/com/oracle/svm/core/jdk15/Target_java_lang_Module_JDK15OrLater.java rename to substratevm/src/com.oracle.svm.core.jdk17/src/com/oracle/svm/core/jdk17/Target_java_lang_Module_JDK17OrLater.java index 94a0719002f1..787a9785d78a 100644 --- a/substratevm/src/com.oracle.svm.core.jdk15/src/com/oracle/svm/core/jdk15/Target_java_lang_Module_JDK15OrLater.java +++ b/substratevm/src/com.oracle.svm.core.jdk17/src/com/oracle/svm/core/jdk17/Target_java_lang_Module_JDK17OrLater.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk15; +package com.oracle.svm.core.jdk17; import java.util.Arrays; import java.util.List; @@ -31,14 +31,14 @@ import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; -import com.oracle.svm.core.jdk.JDK15OrLater; +import com.oracle.svm.core.jdk.JDK17OrLater; import com.oracle.svm.core.jdk11.ModuleUtil; @SuppressWarnings("unused") -@TargetClass(value = Module.class, onlyWith = JDK15OrLater.class) -public final class Target_java_lang_Module_JDK15OrLater { +@TargetClass(value = Module.class, onlyWith = JDK17OrLater.class) +public final class Target_java_lang_Module_JDK17OrLater { - //Checkstyle: allow synchronization + // Checkstyle: allow synchronization @Substitute private static void defineModule0(Module module, boolean isOpen, String version, String location, Object[] pns) { if (Arrays.stream(pns).anyMatch(Objects::isNull)) { diff --git a/substratevm/src/com.oracle.svm.core.jdk14/src/com/oracle/svm/core/jdk14/Target_java_nio_DirectByteBuffer_JDK14OrLater.java b/substratevm/src/com.oracle.svm.core.jdk17/src/com/oracle/svm/core/jdk17/Target_java_nio_DirectByteBuffer_JDK17OrLater.java similarity index 76% rename from substratevm/src/com.oracle.svm.core.jdk14/src/com/oracle/svm/core/jdk14/Target_java_nio_DirectByteBuffer_JDK14OrLater.java rename to substratevm/src/com.oracle.svm.core.jdk17/src/com/oracle/svm/core/jdk17/Target_java_nio_DirectByteBuffer_JDK17OrLater.java index 9fc54b52b726..122b63bccbed 100644 --- a/substratevm/src/com.oracle.svm.core.jdk14/src/com/oracle/svm/core/jdk14/Target_java_nio_DirectByteBuffer_JDK14OrLater.java +++ b/substratevm/src/com.oracle.svm.core.jdk17/src/com/oracle/svm/core/jdk17/Target_java_nio_DirectByteBuffer_JDK17OrLater.java @@ -22,48 +22,48 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk14; +package com.oracle.svm.core.jdk17; import java.io.FileDescriptor; import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; -import com.oracle.svm.core.jdk.JDK14OrLater; +import com.oracle.svm.core.jdk.JDK17OrLater; import jdk.internal.access.foreign.MemorySegmentProxy; -@TargetClass(className = "java.nio.DirectByteBuffer", onlyWith = JDK14OrLater.class) +@TargetClass(className = "java.nio.DirectByteBuffer", onlyWith = JDK17OrLater.class) @SuppressWarnings("unused") -final class Target_java_nio_DirectByteBuffer_JDK14OrLater { +final class Target_java_nio_DirectByteBuffer_JDK17OrLater { @Alias - protected Target_java_nio_DirectByteBuffer_JDK14OrLater(int cap, long addr, FileDescriptor fd, Runnable unmapper, boolean isSync, MemorySegmentProxy segment) { + protected Target_java_nio_DirectByteBuffer_JDK17OrLater(int cap, long addr, FileDescriptor fd, Runnable unmapper, boolean isSync, MemorySegmentProxy segment) { } } -@TargetClass(className = "java.nio.DirectByteBufferR", onlyWith = JDK14OrLater.class) +@TargetClass(className = "java.nio.DirectByteBufferR", onlyWith = JDK17OrLater.class) @SuppressWarnings("unused") -final class Target_java_nio_DirectByteBufferR_JDK14OrLater { +final class Target_java_nio_DirectByteBufferR_JDK17OrLater { @Alias - protected Target_java_nio_DirectByteBufferR_JDK14OrLater(int cap, long addr, FileDescriptor fd, Runnable unmapper, boolean isSync, MemorySegmentProxy segment) { + protected Target_java_nio_DirectByteBufferR_JDK17OrLater(int cap, long addr, FileDescriptor fd, Runnable unmapper, boolean isSync, MemorySegmentProxy segment) { } } -@TargetClass(className = "sun.nio.ch.Util", onlyWith = JDK14OrLater.class) +@TargetClass(className = "sun.nio.ch.Util", onlyWith = JDK17OrLater.class) final class Target_sun_nio_ch_Util { @Substitute - private static Target_java_nio_DirectByteBuffer_JDK14OrLater newMappedByteBuffer(int size, long addr, FileDescriptor fd, Runnable unmapper, boolean isSync) { - return new Target_java_nio_DirectByteBuffer_JDK14OrLater(size, addr, fd, unmapper, isSync, null); + private static Target_java_nio_DirectByteBuffer_JDK17OrLater newMappedByteBuffer(int size, long addr, FileDescriptor fd, Runnable unmapper, boolean isSync) { + return new Target_java_nio_DirectByteBuffer_JDK17OrLater(size, addr, fd, unmapper, isSync, null); } @Substitute - static Target_java_nio_DirectByteBufferR_JDK14OrLater newMappedByteBufferR(int size, long addr, FileDescriptor fd, Runnable unmapper, boolean isSync) { - return new Target_java_nio_DirectByteBufferR_JDK14OrLater(size, addr, fd, unmapper, isSync, null); + static Target_java_nio_DirectByteBufferR_JDK17OrLater newMappedByteBufferR(int size, long addr, FileDescriptor fd, Runnable unmapper, boolean isSync) { + return new Target_java_nio_DirectByteBufferR_JDK17OrLater(size, addr, fd, unmapper, isSync, null); } } diff --git a/substratevm/src/com.oracle.svm.core.jdk15/src/com/oracle/svm/core/jdk15/Target_jdk_internal_loader_BootLoader_JDK15OrLater.java b/substratevm/src/com.oracle.svm.core.jdk17/src/com/oracle/svm/core/jdk17/Target_jdk_internal_loader_BootLoader_JDK17OrLater.java similarity index 89% rename from substratevm/src/com.oracle.svm.core.jdk15/src/com/oracle/svm/core/jdk15/Target_jdk_internal_loader_BootLoader_JDK15OrLater.java rename to substratevm/src/com.oracle.svm.core.jdk17/src/com/oracle/svm/core/jdk17/Target_jdk_internal_loader_BootLoader_JDK17OrLater.java index 09c1e91120f3..b44b604085b7 100644 --- a/substratevm/src/com.oracle.svm.core.jdk15/src/com/oracle/svm/core/jdk15/Target_jdk_internal_loader_BootLoader_JDK15OrLater.java +++ b/substratevm/src/com.oracle.svm.core.jdk17/src/com/oracle/svm/core/jdk17/Target_jdk_internal_loader_BootLoader_JDK17OrLater.java @@ -22,14 +22,14 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk15; +package com.oracle.svm.core.jdk17; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; -import com.oracle.svm.core.jdk.JDK15OrLater; +import com.oracle.svm.core.jdk.JDK17OrLater; -@TargetClass(className = "jdk.internal.loader.BootLoader", onlyWith = JDK15OrLater.class) -final class Target_jdk_internal_loader_BootLoader_JDK15OrLater { +@TargetClass(className = "jdk.internal.loader.BootLoader", onlyWith = JDK17OrLater.class) +final class Target_jdk_internal_loader_BootLoader_JDK17OrLater { @SuppressWarnings("unused") @Substitute diff --git a/substratevm/src/com.oracle.svm.core.jdk17/src/com/oracle/svm/core/jdk17/Target_jdk_internal_platform_CgroupMetrics_JDK17OrLater.java b/substratevm/src/com.oracle.svm.core.jdk17/src/com/oracle/svm/core/jdk17/Target_jdk_internal_platform_CgroupMetrics_JDK17OrLater.java index fcc653fdb16d..5f1ba4730b17 100644 --- a/substratevm/src/com.oracle.svm.core.jdk17/src/com/oracle/svm/core/jdk17/Target_jdk_internal_platform_CgroupMetrics_JDK17OrLater.java +++ b/substratevm/src/com.oracle.svm.core.jdk17/src/com/oracle/svm/core/jdk17/Target_jdk_internal_platform_CgroupMetrics_JDK17OrLater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java index 14edd6ac3147..4a407624f6c1 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java @@ -60,8 +60,8 @@ public void afterRegistration(AfterRegistrationAccess access) { } class PosixSubstrateSegfaultHandler extends SubstrateSegfaultHandler { - @CEntryPoint - @CEntryPointOptions(prologue = NoPrologue.class, epilogue = NoEpilogue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = NoPrologue.class, epilogue = NoEpilogue.class, publishAs = Publish.NotPublished) @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate in segfault signal handler.") @Uninterruptible(reason = "Must be uninterruptible until it gets immune to safepoints") private static void dispatch(@SuppressWarnings("unused") int signalNumber, @SuppressWarnings("unused") siginfo_t sigInfo, ucontext_t uContext) { diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/SunMiscSubstitutions.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/SunMiscSubstitutions.java index 18130398b026..b4e3799697d9 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/SunMiscSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/SunMiscSubstitutions.java @@ -136,6 +136,9 @@ private Util_jdk_internal_misc_Signal() { * signals that the VM itself uses. */ static long handle0(int sig, long nativeH) { + if (!SubstrateOptions.EnableSignalHandling.getValue()) { + return sunMiscSignalIgnoreHandler; + } ensureInitialized(); final Signal.SignalDispatcher newDispatcher = nativeHToDispatcher(nativeH); /* If the dispatcher is the CSunMiscSignal handler, then check if the signal is in range. */ diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64DarwinUContextRegisterDumper.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64DarwinUContextRegisterDumper.java new file mode 100644 index 000000000000..5339e5ad84ec --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64DarwinUContextRegisterDumper.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.posix.aarch64; + +import static com.oracle.svm.core.RegisterDumper.dumpReg; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.word.PointerBase; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.RegisterDumper; +import com.oracle.svm.core.annotate.AutomaticFeature; +import com.oracle.svm.core.annotate.Uninterruptible; +import com.oracle.svm.core.graal.aarch64.AArch64ReservedRegisters; +import com.oracle.svm.core.log.Log; +import com.oracle.svm.core.posix.UContextRegisterDumper; +import com.oracle.svm.core.posix.headers.Signal; +import com.oracle.svm.core.util.VMError; + +import jdk.vm.ci.aarch64.AArch64; + +@Platforms({Platform.DARWIN_AARCH64.class, Platform.IOS_AARCH64.class}) +@AutomaticFeature +class AArch64DarwinUContextRegisterDumperFeature implements Feature { + @Override + public void afterRegistration(AfterRegistrationAccess access) { + VMError.guarantee(AArch64.r27.equals(AArch64ReservedRegisters.HEAP_BASE_REGISTER_CANDIDATE)); + VMError.guarantee(AArch64.r28.equals(AArch64ReservedRegisters.THREAD_REGISTER_CANDIDATE)); + ImageSingletons.add(RegisterDumper.class, new AArch64DarwinUContextRegisterDumper()); + } +} + +public class AArch64DarwinUContextRegisterDumper implements UContextRegisterDumper { + @Override + public void dumpRegisters(Log log, Signal.ucontext_t uContext, boolean printLocationInfo, boolean allowJavaHeapAccess, boolean allowUnsafeOperations) { + Signal.AArch64DarwinMContext64 sigcontext = uContext.uc_mcontext_darwin_aarch64(); + Signal.GregsPointer regs = sigcontext.regs(); + dumpReg(log, "R0 ", regs.read(0), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R1 ", regs.read(1), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R2 ", regs.read(2), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R3 ", regs.read(3), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R4 ", regs.read(4), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R5 ", regs.read(5), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R6 ", regs.read(6), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R7 ", regs.read(7), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R8 ", regs.read(8), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R9 ", regs.read(9), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R10 ", regs.read(10), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R11 ", regs.read(11), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R12 ", regs.read(12), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R13 ", regs.read(13), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R14 ", regs.read(14), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R15 ", regs.read(15), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R16 ", regs.read(16), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R17 ", regs.read(17), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R18 ", regs.read(18), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R19 ", regs.read(19), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R20 ", regs.read(20), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R21 ", regs.read(21), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R22 ", regs.read(22), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R23 ", regs.read(23), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R24 ", regs.read(24), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R25 ", regs.read(25), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R26 ", regs.read(26), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R27 ", regs.read(27), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R28 ", regs.read(28), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R29 ", sigcontext.fp(), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R30 ", sigcontext.lr(), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "SP ", sigcontext.sp(), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "PC ", sigcontext.pc(), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code", mayBeInlined = true) + public PointerBase getHeapBase(Signal.ucontext_t uContext) { + Signal.AArch64DarwinMContext64 sigcontext = uContext.uc_mcontext_darwin_aarch64(); + return WordFactory.pointer(sigcontext.regs().read(27)); + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code", mayBeInlined = true) + public PointerBase getThreadPointer(Signal.ucontext_t uContext) { + Signal.AArch64DarwinMContext64 sigcontext = uContext.uc_mcontext_darwin_aarch64(); + return WordFactory.pointer(sigcontext.regs().read(28)); + } + + @Override + public PointerBase getSP(Signal.ucontext_t uContext) { + Signal.AArch64DarwinMContext64 sigcontext = uContext.uc_mcontext_darwin_aarch64(); + return WordFactory.pointer(sigcontext.sp()); + } + + @Override + public PointerBase getIP(Signal.ucontext_t uContext) { + Signal.AArch64DarwinMContext64 sigcontext = uContext.uc_mcontext_darwin_aarch64(); + return WordFactory.pointer(sigcontext.pc()); + } +} diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64UContextRegisterDumper.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64LinuxUContextRegisterDumper.java similarity index 90% rename from substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64UContextRegisterDumper.java rename to substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64LinuxUContextRegisterDumper.java index b3c643e630b6..235d1e157234 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64UContextRegisterDumper.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64LinuxUContextRegisterDumper.java @@ -40,7 +40,7 @@ import com.oracle.svm.core.log.Log; import com.oracle.svm.core.posix.UContextRegisterDumper; import com.oracle.svm.core.posix.headers.Signal.GregsPointer; -import com.oracle.svm.core.posix.headers.Signal.mcontext_t; +import com.oracle.svm.core.posix.headers.Signal.mcontext_linux_aarch64_t; import com.oracle.svm.core.posix.headers.Signal.ucontext_t; import com.oracle.svm.core.util.VMError; @@ -48,19 +48,19 @@ @Platforms({Platform.LINUX_AARCH64.class, Platform.ANDROID_AARCH64.class}) @AutomaticFeature -class AArch64UContextRegisterDumperFeature implements Feature { +class AArch64LinuxUContextRegisterDumperFeature implements Feature { @Override public void afterRegistration(AfterRegistrationAccess access) { VMError.guarantee(AArch64.r27.equals(AArch64ReservedRegisters.HEAP_BASE_REGISTER_CANDIDATE)); VMError.guarantee(AArch64.r28.equals(AArch64ReservedRegisters.THREAD_REGISTER_CANDIDATE)); - ImageSingletons.add(RegisterDumper.class, new AArch64UContextRegisterDumper()); + ImageSingletons.add(RegisterDumper.class, new AArch64LinuxUContextRegisterDumper()); } } -class AArch64UContextRegisterDumper implements UContextRegisterDumper { +class AArch64LinuxUContextRegisterDumper implements UContextRegisterDumper { @Override public void dumpRegisters(Log log, ucontext_t uContext, boolean printLocationInfo, boolean allowJavaHeapAccess, boolean allowUnsafeOperations) { - mcontext_t sigcontext = uContext.uc_mcontext(); + mcontext_linux_aarch64_t sigcontext = uContext.uc_mcontext_linux_aarch64(); GregsPointer regs = sigcontext.regs(); dumpReg(log, "R0 ", regs.read(0), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); dumpReg(log, "R1 ", regs.read(1), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); @@ -100,26 +100,26 @@ public void dumpRegisters(Log log, ucontext_t uContext, boolean printLocationInf @Override @Uninterruptible(reason = "Called from uninterruptible code", mayBeInlined = true) public PointerBase getHeapBase(ucontext_t uContext) { - GregsPointer regs = uContext.uc_mcontext().regs(); + GregsPointer regs = uContext.uc_mcontext_linux_aarch64().regs(); return WordFactory.pointer(regs.read(27)); } @Override @Uninterruptible(reason = "Called from uninterruptible code", mayBeInlined = true) public PointerBase getThreadPointer(ucontext_t uContext) { - GregsPointer regs = uContext.uc_mcontext().regs(); + GregsPointer regs = uContext.uc_mcontext_linux_aarch64().regs(); return WordFactory.pointer(regs.read(28)); } @Override public PointerBase getSP(ucontext_t uContext) { - mcontext_t sigcontext = uContext.uc_mcontext(); + mcontext_linux_aarch64_t sigcontext = uContext.uc_mcontext_linux_aarch64(); return WordFactory.pointer(sigcontext.sp()); } @Override public PointerBase getIP(ucontext_t uContext) { - mcontext_t sigcontext = uContext.uc_mcontext(); + mcontext_linux_aarch64_t sigcontext = uContext.uc_mcontext_linux_aarch64(); return WordFactory.pointer(sigcontext.pc()); } } diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinUContextRegisterDumper.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64DarwinUContextRegisterDumper.java similarity index 88% rename from substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinUContextRegisterDumper.java rename to substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64DarwinUContextRegisterDumper.java index d3005a855363..ee6a6b101245 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinUContextRegisterDumper.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64DarwinUContextRegisterDumper.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.posix.darwin; +package com.oracle.svm.core.posix.amd64; import static com.oracle.svm.core.RegisterDumper.dumpReg; @@ -45,21 +45,21 @@ import jdk.vm.ci.amd64.AMD64; -@Platforms({Platform.DARWIN.class}) +@Platforms({Platform.DARWIN_AMD64.class}) @AutomaticFeature -class DarwinUContextRegisterDumperFeature implements Feature { +class AMD64DarwinUContextRegisterDumperFeature implements Feature { @Override public void afterRegistration(AfterRegistrationAccess access) { VMError.guarantee(AMD64.r14.equals(AMD64ReservedRegisters.HEAP_BASE_REGISTER_CANDIDATE)); VMError.guarantee(AMD64.r15.equals(AMD64ReservedRegisters.THREAD_REGISTER_CANDIDATE)); - ImageSingletons.add(RegisterDumper.class, new DarwinUContextRegisterDumper()); + ImageSingletons.add(RegisterDumper.class, new AMD64DarwinUContextRegisterDumper()); } } -class DarwinUContextRegisterDumper implements UContextRegisterDumper { +class AMD64DarwinUContextRegisterDumper implements UContextRegisterDumper { @Override public void dumpRegisters(Log log, ucontext_t uContext, boolean printLocationInfo, boolean allowJavaHeapAccess, boolean allowUnsafeOperations) { - Signal.MContext64 sigcontext = uContext.uc_mcontext64(); + Signal.AMD64DarwinMContext64 sigcontext = uContext.uc_mcontext_darwin_amd64(); dumpReg(log, "RAX ", ((Pointer) sigcontext).readLong(sigcontext.rax_offset()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); dumpReg(log, "RBX ", ((Pointer) sigcontext).readLong(sigcontext.rbx_offset()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); dumpReg(log, "RCX ", ((Pointer) sigcontext).readLong(sigcontext.rcx_offset()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); @@ -83,26 +83,26 @@ public void dumpRegisters(Log log, ucontext_t uContext, boolean printLocationInf @Override @Uninterruptible(reason = "Called from uninterruptible code", mayBeInlined = true) public PointerBase getHeapBase(ucontext_t uContext) { - Signal.MContext64 sigcontext = uContext.uc_mcontext64(); + Signal.AMD64DarwinMContext64 sigcontext = uContext.uc_mcontext_darwin_amd64(); return ((Pointer) sigcontext).readWord(sigcontext.r14_offset()); } @Override @Uninterruptible(reason = "Called from uninterruptible code", mayBeInlined = true) public PointerBase getThreadPointer(ucontext_t uContext) { - Signal.MContext64 sigcontext = uContext.uc_mcontext64(); + Signal.AMD64DarwinMContext64 sigcontext = uContext.uc_mcontext_darwin_amd64(); return ((Pointer) sigcontext).readWord(sigcontext.r15_offset()); } @Override public PointerBase getSP(ucontext_t uContext) { - Signal.MContext64 sigcontext = uContext.uc_mcontext64(); + Signal.AMD64DarwinMContext64 sigcontext = uContext.uc_mcontext_darwin_amd64(); return ((Pointer) sigcontext).readWord(sigcontext.rsp_offset()); } @Override public PointerBase getIP(ucontext_t uContext) { - Signal.MContext64 sigcontext = uContext.uc_mcontext64(); + Signal.AMD64DarwinMContext64 sigcontext = uContext.uc_mcontext_darwin_amd64(); return ((Pointer) sigcontext).readWord(sigcontext.rip_offset()); } } diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64LinuxUContextRegisterDumper.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64LinuxUContextRegisterDumper.java new file mode 100644 index 000000000000..ca6a660c6bb9 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64LinuxUContextRegisterDumper.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.posix.amd64; + +import static com.oracle.svm.core.RegisterDumper.dumpReg; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.word.PointerBase; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.RegisterDumper; +import com.oracle.svm.core.annotate.AutomaticFeature; +import com.oracle.svm.core.annotate.Uninterruptible; +import com.oracle.svm.core.graal.amd64.AMD64ReservedRegisters; +import com.oracle.svm.core.log.Log; +import com.oracle.svm.core.posix.UContextRegisterDumper; +import com.oracle.svm.core.posix.headers.Signal.GregEnumLinuxAMD64; +import com.oracle.svm.core.posix.headers.Signal.GregsPointer; +import com.oracle.svm.core.posix.headers.Signal.ucontext_t; +import com.oracle.svm.core.util.VMError; + +import jdk.vm.ci.amd64.AMD64; + +@Platforms({Platform.LINUX_AMD64.class}) +@AutomaticFeature +class AMD64LinuxUContextRegisterDumperFeature implements Feature { + @Override + public void afterRegistration(AfterRegistrationAccess access) { + VMError.guarantee(AMD64.r14.equals(AMD64ReservedRegisters.HEAP_BASE_REGISTER_CANDIDATE)); + VMError.guarantee(AMD64.r15.equals(AMD64ReservedRegisters.THREAD_REGISTER_CANDIDATE)); + ImageSingletons.add(RegisterDumper.class, new AMD64LinuxUContextRegisterDumper()); + } +} + +class AMD64LinuxUContextRegisterDumper implements UContextRegisterDumper { + @Override + public void dumpRegisters(Log log, ucontext_t uContext, boolean printLocationInfo, boolean allowJavaHeapAccess, boolean allowUnsafeOperations) { + GregsPointer gregs = uContext.uc_mcontext_linux_amd64_gregs(); + dumpReg(log, "RAX ", gregs.read(GregEnumLinuxAMD64.REG_RAX()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "RBX ", gregs.read(GregEnumLinuxAMD64.REG_RBX()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "RCX ", gregs.read(GregEnumLinuxAMD64.REG_RCX()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "RDX ", gregs.read(GregEnumLinuxAMD64.REG_RDX()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "RBP ", gregs.read(GregEnumLinuxAMD64.REG_RBP()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "RSI ", gregs.read(GregEnumLinuxAMD64.REG_RSI()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "RDI ", gregs.read(GregEnumLinuxAMD64.REG_RDI()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "RSP ", gregs.read(GregEnumLinuxAMD64.REG_RSP()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R8 ", gregs.read(GregEnumLinuxAMD64.REG_R8()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R9 ", gregs.read(GregEnumLinuxAMD64.REG_R9()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R10 ", gregs.read(GregEnumLinuxAMD64.REG_R10()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R11 ", gregs.read(GregEnumLinuxAMD64.REG_R11()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R12 ", gregs.read(GregEnumLinuxAMD64.REG_R12()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R13 ", gregs.read(GregEnumLinuxAMD64.REG_R13()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R14 ", gregs.read(GregEnumLinuxAMD64.REG_R14()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "R15 ", gregs.read(GregEnumLinuxAMD64.REG_R15()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "EFL ", gregs.read(GregEnumLinuxAMD64.REG_EFL()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + dumpReg(log, "RIP ", gregs.read(GregEnumLinuxAMD64.REG_RIP()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code", mayBeInlined = true, calleeMustBe = false) + public PointerBase getHeapBase(ucontext_t uContext) { + GregsPointer gregs = uContext.uc_mcontext_linux_amd64_gregs(); + return WordFactory.pointer(gregs.read(GregEnumLinuxAMD64.REG_R14())); + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code", mayBeInlined = true, calleeMustBe = false) + public PointerBase getThreadPointer(ucontext_t uContext) { + GregsPointer gregs = uContext.uc_mcontext_linux_amd64_gregs(); + return WordFactory.pointer(gregs.read(GregEnumLinuxAMD64.REG_R15())); + } + + @Override + public PointerBase getSP(ucontext_t uContext) { + GregsPointer gregs = uContext.uc_mcontext_linux_amd64_gregs(); + return WordFactory.pointer(gregs.read(GregEnumLinuxAMD64.REG_RSP())); + } + + @Override + public PointerBase getIP(ucontext_t uContext) { + GregsPointer gregs = uContext.uc_mcontext_linux_amd64_gregs(); + return WordFactory.pointer(gregs.read(GregEnumLinuxAMD64.REG_RIP())); + } +} diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64UContextRegisterDumper.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64UContextRegisterDumper.java deleted file mode 100644 index a4c6a205dd14..000000000000 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64UContextRegisterDumper.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.posix.amd64; - -import static com.oracle.svm.core.RegisterDumper.dumpReg; - -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.hosted.Feature; -import org.graalvm.word.PointerBase; -import org.graalvm.word.WordFactory; - -import com.oracle.svm.core.RegisterDumper; -import com.oracle.svm.core.annotate.AutomaticFeature; -import com.oracle.svm.core.annotate.Uninterruptible; -import com.oracle.svm.core.graal.amd64.AMD64ReservedRegisters; -import com.oracle.svm.core.log.Log; -import com.oracle.svm.core.posix.UContextRegisterDumper; -import com.oracle.svm.core.posix.headers.Signal.GregEnum; -import com.oracle.svm.core.posix.headers.Signal.GregsPointer; -import com.oracle.svm.core.posix.headers.Signal.ucontext_t; -import com.oracle.svm.core.util.VMError; - -import jdk.vm.ci.amd64.AMD64; - -@Platforms({Platform.LINUX_AMD64.class}) -@AutomaticFeature -class AMD64UContextRegisterDumperFeature implements Feature { - @Override - public void afterRegistration(AfterRegistrationAccess access) { - VMError.guarantee(AMD64.r14.equals(AMD64ReservedRegisters.HEAP_BASE_REGISTER_CANDIDATE)); - VMError.guarantee(AMD64.r15.equals(AMD64ReservedRegisters.THREAD_REGISTER_CANDIDATE)); - ImageSingletons.add(RegisterDumper.class, new AMD64UContextRegisterDumper()); - } -} - -class AMD64UContextRegisterDumper implements UContextRegisterDumper { - @Override - public void dumpRegisters(Log log, ucontext_t uContext, boolean printLocationInfo, boolean allowJavaHeapAccess, boolean allowUnsafeOperations) { - GregsPointer gregs = uContext.uc_mcontext_gregs(); - dumpReg(log, "RAX ", gregs.read(GregEnum.REG_RAX()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); - dumpReg(log, "RBX ", gregs.read(GregEnum.REG_RBX()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); - dumpReg(log, "RCX ", gregs.read(GregEnum.REG_RCX()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); - dumpReg(log, "RDX ", gregs.read(GregEnum.REG_RDX()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); - dumpReg(log, "RBP ", gregs.read(GregEnum.REG_RBP()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); - dumpReg(log, "RSI ", gregs.read(GregEnum.REG_RSI()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); - dumpReg(log, "RDI ", gregs.read(GregEnum.REG_RDI()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); - dumpReg(log, "RSP ", gregs.read(GregEnum.REG_RSP()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); - dumpReg(log, "R8 ", gregs.read(GregEnum.REG_R8()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); - dumpReg(log, "R9 ", gregs.read(GregEnum.REG_R9()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); - dumpReg(log, "R10 ", gregs.read(GregEnum.REG_R10()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); - dumpReg(log, "R11 ", gregs.read(GregEnum.REG_R11()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); - dumpReg(log, "R12 ", gregs.read(GregEnum.REG_R12()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); - dumpReg(log, "R13 ", gregs.read(GregEnum.REG_R13()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); - dumpReg(log, "R14 ", gregs.read(GregEnum.REG_R14()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); - dumpReg(log, "R15 ", gregs.read(GregEnum.REG_R15()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); - dumpReg(log, "EFL ", gregs.read(GregEnum.REG_EFL()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); - dumpReg(log, "RIP ", gregs.read(GregEnum.REG_RIP()), printLocationInfo, allowJavaHeapAccess, allowUnsafeOperations); - } - - @Override - @Uninterruptible(reason = "Called from uninterruptible code", mayBeInlined = true, calleeMustBe = false) - public PointerBase getHeapBase(ucontext_t uContext) { - GregsPointer gregs = uContext.uc_mcontext_gregs(); - return WordFactory.pointer(gregs.read(GregEnum.REG_R14())); - } - - @Override - @Uninterruptible(reason = "Called from uninterruptible code", mayBeInlined = true, calleeMustBe = false) - public PointerBase getThreadPointer(ucontext_t uContext) { - GregsPointer gregs = uContext.uc_mcontext_gregs(); - return WordFactory.pointer(gregs.read(GregEnum.REG_R15())); - } - - @Override - public PointerBase getSP(ucontext_t uContext) { - GregsPointer gregs = uContext.uc_mcontext_gregs(); - return WordFactory.pointer(gregs.read(GregEnum.REG_RSP())); - } - - @Override - public PointerBase getIP(ucontext_t uContext) { - GregsPointer gregs = uContext.uc_mcontext_gregs(); - return WordFactory.pointer(gregs.read(GregEnum.REG_RIP())); - } -} diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Sched.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Sched.java index 20d98e2166dd..660a90989c79 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Sched.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Sched.java @@ -37,4 +37,9 @@ public class Sched { @CFunction public static native int sched_yield(); + + public static class NoTransitions { + @CFunction(transition = CFunction.Transition.NO_TRANSITION) + public static native int sched_yield(); + } } diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Signal.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Signal.java index d73b4df2b867..c469a16d391a 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Signal.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Signal.java @@ -110,19 +110,149 @@ public interface siginfo_t extends PointerBase { VoidPointer si_addr(); } - @Platforms(Platform.LINUX.class) + @Platforms({Platform.LINUX.class, Platform.DARWIN_AARCH64.class, Platform.IOS_AARCH64.class}) @CPointerTo(nameOfCType = "long long int") public interface GregsPointer extends PointerBase { long read(int index); } + @CStruct + public interface ucontext_t extends RegisterDumper.Context { + @CFieldAddress("uc_mcontext.gregs") + @Platforms({Platform.LINUX_AMD64.class}) + GregsPointer uc_mcontext_linux_amd64_gregs(); + + @CFieldAddress("uc_mcontext") + @Platforms({Platform.LINUX_AARCH64.class, Platform.ANDROID_AARCH64.class}) + mcontext_linux_aarch64_t uc_mcontext_linux_aarch64(); + + @CField("uc_mcontext") + @Platforms({Platform.DARWIN_AMD64.class}) + AMD64DarwinMContext64 uc_mcontext_darwin_amd64(); + + @CField("uc_mcontext") + @Platforms({Platform.DARWIN_AARCH64.class, Platform.IOS_AARCH64.class}) + AArch64DarwinMContext64 uc_mcontext_darwin_aarch64(); + } + + public interface AdvancedSignalDispatcher extends CFunctionPointer { + @InvokeCFunctionPointer + void dispatch(int signum, siginfo_t siginfo, WordPointer opaque); + } + + @CConstant + public static native int SA_RESTART(); + + @CConstant + public static native int SA_SIGINFO(); + + @CConstant + public static native int SA_NODEFER(); + + @CStruct(addStructKeyword = true) + public interface sigaction extends PointerBase { + @CField + SignalDispatcher sa_handler(); + + @CField + void sa_handler(SignalDispatcher value); + + @CField + AdvancedSignalDispatcher sa_sigaction(); + + @CField + void sa_sigaction(AdvancedSignalDispatcher value); + + @CField + int sa_flags(); + + @CField + void sa_flags(int value); + + @CFieldAddress + sigset_tPointer sa_mask(); + } + + /** @param signum from {@link SignalEnum#getCValue()} */ + @CFunction + public static native int sigaction(int signum, sigaction act, sigaction oldact); + + @CEnum + @CContext(PosixDirectives.class) + public enum SignalEnum { + SIGABRT, + SIGALRM, + SIGBUS, + SIGCHLD, + SIGCONT, + SIGFPE, + SIGHUP, + SIGILL, + SIGINT, + SIGIO, + SIGIOT, + SIGKILL, + SIGPIPE, + SIGPROF, + SIGQUIT, + SIGSEGV, + SIGSTOP, + SIGSYS, + SIGTERM, + SIGTRAP, + SIGTSTP, + SIGTTIN, + SIGTTOU, + SIGURG, + SIGUSR1, + SIGUSR2, + SIGVTALRM, + SIGWINCH, + SIGXCPU, + SIGXFSZ; + + @CEnumValue + public native int getCValue(); + } + + @Platforms(Platform.LINUX.class) + @CEnum + @CContext(PosixDirectives.class) + public enum LinuxSignalEnum { + SIGPOLL, + SIGPWR; + + @CEnumValue + public native int getCValue(); + } + + @Platforms(Platform.DARWIN.class) + @CEnum + @CContext(PosixDirectives.class) + public enum DarwinSignalEnum { + SIGINFO, + SIGEMT; + + @CEnumValue + public native int getCValue(); + } + + @CFunction + public static native int sigemptyset(sigset_tPointer set); + + @CFunction + public static native int sigaddset(sigset_tPointer set, int signum); + /** * Used in {@link SubstrateSegfaultHandler}. So, this must not be a {@link CEnum} as this would * result in machine code that needs a proper a heap base. + * + * Information about Linux's AMD64 struct sigcontext_64 uc_mcontext can be found at + * https://github.com/torvalds/linux/blob/9e1ff307c779ce1f0f810c7ecce3d95bbae40896/arch/x86/include/uapi/asm/sigcontext.h#L238 */ @Platforms({Platform.LINUX_AMD64.class}) @CContext(PosixDirectives.class) - public static final class GregEnum { + public static final class GregEnumLinuxAMD64 { @CConstant public static native int REG_R8(); @@ -193,25 +323,39 @@ public static final class GregEnum { public static native int REG_CR2(); } - @CStruct - public interface ucontext_t extends RegisterDumper.Context { - @CFieldAddress("uc_mcontext.gregs") - @Platforms({Platform.LINUX_AMD64.class}) - GregsPointer uc_mcontext_gregs(); + /** + * Information about Linux's AArch64 struct sigcontext uc_mcontext can be found at + * https://github.com/torvalds/linux/blob/9e1ff307c779ce1f0f810c7ecce3d95bbae40896/arch/arm64/include/uapi/asm/sigcontext.h#L28 + */ + @CStruct(value = "mcontext_t") + @Platforms({Platform.LINUX_AARCH64.class, Platform.ANDROID_AARCH64.class}) + public interface mcontext_linux_aarch64_t extends PointerBase { + @CField + long fault_address(); - @CFieldAddress("uc_mcontext") - @Platforms({Platform.LINUX_AARCH64.class, Platform.ANDROID_AARCH64.class}) - mcontext_t uc_mcontext(); + @CFieldAddress + GregsPointer regs(); - @CField("uc_mcontext") - @Platforms({Platform.DARWIN.class}) - MContext64 uc_mcontext64(); + @CField + long sp(); + + @CField + long pc(); + + @CField + long pstate(); } - @Platforms({Platform.DARWIN.class}) + /** + * Information about Darwin's AMD64 mcontext64 can be found at + * https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/i386/_mcontext.h#L147 + * + * Information about _STRUCT_X86_THREAD_STATE64 can be found at + * https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/osfmk/mach/i386/_structs.h#L739 + */ + @Platforms({Platform.DARWIN_AMD64.class}) @CStruct(value = "__darwin_mcontext64", addStructKeyword = true) - public interface MContext64 extends PointerBase { - + public interface AMD64DarwinMContext64 extends PointerBase { @CFieldOffset("__ss.__rax") int rax_offset(); @@ -267,130 +411,30 @@ public interface MContext64 extends PointerBase { int efl_offset(); } - @CStruct - @Platforms({Platform.LINUX_AARCH64.class, Platform.ANDROID_AARCH64.class}) - public interface mcontext_t extends PointerBase { - @CField - long fault_address(); - - @CFieldAddress + /** + * Information about Darwin's AArch64 mcontext64 can be found at + * https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/arm/_mcontext.h#L70 + * + * Information about _STRUCT_ARM_THREAD_STATE64 can be found at + * https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/osfmk/mach/arm/_structs.h#L102 + */ + @Platforms({Platform.DARWIN_AARCH64.class, Platform.IOS_AARCH64.class}) + @CStruct(value = "__darwin_mcontext64", addStructKeyword = true) + public interface AArch64DarwinMContext64 extends PointerBase { + @CFieldAddress("__ss.__x") GregsPointer regs(); - @CField - long sp(); - - @CField - long pc(); - - @CField - long pstate(); - } - - public interface AdvancedSignalDispatcher extends CFunctionPointer { - @InvokeCFunctionPointer - void dispatch(int signum, siginfo_t siginfo, WordPointer opaque); - } - - @CConstant - public static native int SA_RESTART(); - - @CConstant - public static native int SA_SIGINFO(); - - @CConstant - public static native int SA_NODEFER(); - - @CStruct(addStructKeyword = true) - public interface sigaction extends PointerBase { - @CField - SignalDispatcher sa_handler(); - - @CField - void sa_handler(SignalDispatcher value); - - @CField - AdvancedSignalDispatcher sa_sigaction(); + @CField("__ss.__fp") + long fp(); - @CField - void sa_sigaction(AdvancedSignalDispatcher value); - - @CField - int sa_flags(); + @CField("__ss.__lr") + long lr(); - @CField - void sa_flags(int value); - - @CFieldAddress - sigset_tPointer sa_mask(); - } - - /** @param signum from {@link SignalEnum#getCValue()} */ - @CFunction - public static native int sigaction(int signum, sigaction act, sigaction oldact); - - @CEnum - @CContext(PosixDirectives.class) - public enum SignalEnum { - SIGABRT, - SIGALRM, - SIGBUS, - SIGCHLD, - SIGCONT, - SIGFPE, - SIGHUP, - SIGILL, - SIGINT, - SIGIO, - SIGIOT, - SIGKILL, - SIGPIPE, - SIGPROF, - SIGQUIT, - SIGSEGV, - SIGSTOP, - SIGSYS, - SIGTERM, - SIGTRAP, - SIGTSTP, - SIGTTIN, - SIGTTOU, - SIGURG, - SIGUSR1, - SIGUSR2, - SIGVTALRM, - SIGWINCH, - SIGXCPU, - SIGXFSZ; - - @CEnumValue - public native int getCValue(); - } - - @Platforms(Platform.LINUX.class) - @CEnum - @CContext(PosixDirectives.class) - public enum LinuxSignalEnum { - SIGPOLL, - SIGPWR; - - @CEnumValue - public native int getCValue(); - } - - @Platforms(Platform.DARWIN.class) - @CEnum - @CContext(PosixDirectives.class) - public enum DarwinSignalEnum { - SIGINFO, - SIGEMT; + @CField("__ss.__sp") + long sp(); - @CEnumValue - public native int getCValue(); + @CField("__ss.__pc") + long pc(); } - @CFunction - public static native int sigemptyset(sigset_tPointer set); - - @CFunction - public static native int sigaddset(sigset_tPointer set, int signum); } diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/libc/MuslLibC.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/libc/MuslLibC.java index 3d6dd56c86a1..34921859d4b1 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/libc/MuslLibC.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/libc/MuslLibC.java @@ -49,7 +49,7 @@ public List getAdditionalQueryCodeCompilerOptions() { @Override public String getTargetCompiler() { - return "musl-gcc"; + return "x86_64-linux-musl-gcc"; } @Override diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadVMLockSupport.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadVMLockSupport.java index 8e10d8674795..c443fb18b871 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadVMLockSupport.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadVMLockSupport.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.core.posix.pthread; +import static com.oracle.svm.core.annotate.RestrictHeapAccess.Access.NO_ALLOCATION; + import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.word.Word; @@ -39,6 +41,7 @@ import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.annotate.AutomaticFeature; +import com.oracle.svm.core.annotate.RestrictHeapAccess; import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.annotate.UnknownObjectField; import com.oracle.svm.core.config.ConfigurationValues; @@ -51,7 +54,8 @@ import com.oracle.svm.core.posix.headers.Errno; import com.oracle.svm.core.posix.headers.Pthread; import com.oracle.svm.core.posix.headers.Time; -import com.oracle.svm.core.thread.VMThreads; +import com.oracle.svm.core.stack.StackOverflowCheck; +import com.oracle.svm.core.thread.VMThreads.SafepointBehavior; import jdk.vm.ci.meta.JavaKind; @@ -160,13 +164,16 @@ public static boolean initialize() { } @Uninterruptible(reason = "Called from uninterruptible code.", calleeMustBe = false) + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate in fatal error handling.", overridesCallers = true) protected static void checkResult(int result, String functionName) { if (result != 0) { /* * Functions are called very early and late during our execution, so there is not much * we can do when they fail. */ - VMThreads.StatusSupport.setStatusIgnoreSafepoints(); + SafepointBehavior.preventSafepoints(); + StackOverflowCheck.singleton().disableStackOverflowChecksForFatalError(); + Log.log().string(functionName).string(" returned ").signed(result).newline(); ImageSingletons.lookup(LogHandler.class).fatalError(); } diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixJavaThreads.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixJavaThreads.java index c43b00e95c14..8bb596508002 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixJavaThreads.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixJavaThreads.java @@ -183,8 +183,8 @@ static void enter(ThreadStartData data) { } } - @CEntryPoint - @CEntryPointOptions(prologue = PthreadStartRoutinePrologue.class, epilogue = LeaveDetachThreadEpilogue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = PthreadStartRoutinePrologue.class, epilogue = LeaveDetachThreadEpilogue.class, publishAs = Publish.NotPublished) static WordBase pthreadStartRoutine(ThreadStartData data) { ObjectHandle threadHandle = data.getThreadHandle(); UnmanagedMemory.free(data); diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixVMThreads.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixVMThreads.java index 2d4b08238ae5..dfb7d2c0cb45 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixVMThreads.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixVMThreads.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.posix.thread; +import com.oracle.svm.core.posix.headers.Sched; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.StackValue; import org.graalvm.nativeimage.c.function.CFunction; @@ -76,6 +77,17 @@ public void nativeSleep(int milliseconds) { Time.NoTransitions.nanosleep(ts, WordFactory.nullPointer()); } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + @Override + public void yield() { + Sched.NoTransitions.sched_yield(); + } + + @Override + public boolean supportsPatientSafepoints() { + return true; + } + @Uninterruptible(reason = "Thread state not set up.") @Override protected boolean initializeOnce() { diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsJavaThreads.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsJavaThreads.java index 3f548cd0e44a..6ccec99fb0da 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsJavaThreads.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsJavaThreads.java @@ -127,8 +127,8 @@ static void enter(WindowsThreadStartData data) { } } - @CEntryPoint - @CEntryPointOptions(prologue = OSThreadStartRoutinePrologue.class, epilogue = LeaveDetachThreadEpilogue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = OSThreadStartRoutinePrologue.class, epilogue = LeaveDetachThreadEpilogue.class, publishAs = Publish.NotPublished) static WordBase osThreadStartRoutine(WindowsThreadStartData data) { ObjectHandle threadHandle = data.getThreadHandle(); WinBase.HANDLE osThreadHandle = data.getOSThreadHandle(); diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsProcessPropertiesSupport.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsProcessPropertiesSupport.java index afee09ac495e..0f5704d77964 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsProcessPropertiesSupport.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsProcessPropertiesSupport.java @@ -85,7 +85,7 @@ public void exec(Path executable, String[] args) { @Override public long getProcessID() { - return Process.GetCurrentProcessId(); + return Process.NoTransitions.GetCurrentProcessId(); } @Override @@ -135,11 +135,11 @@ public boolean destroy(long processID) { @Override public boolean destroyForcibly(long processID) { - HANDLE handle = Process.OpenProcess(Process.PROCESS_TERMINATE(), 0, (int) processID); + HANDLE handle = Process.NoTransitions.OpenProcess(Process.PROCESS_TERMINATE(), 0, (int) processID); if (handle.isNull()) { return false; } - boolean result = Process.TerminateProcess(handle, 1) != 0; + boolean result = Process.NoTransitions.TerminateProcess(handle, 1) != 0; WinBase.CloseHandle(handle); return result; } diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java index 1d9788b83e81..52c1c497b65c 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java @@ -44,7 +44,6 @@ import com.oracle.svm.core.c.function.CEntryPointOptions; import com.oracle.svm.core.c.function.CEntryPointOptions.NoEpilogue; import com.oracle.svm.core.c.function.CEntryPointOptions.NoPrologue; -import com.oracle.svm.core.c.function.CEntryPointOptions.NotIncludedAutomatically; import com.oracle.svm.core.c.function.CEntryPointOptions.Publish; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.util.VMError; @@ -89,8 +88,8 @@ protected void installInternal() { private static final CEntryPointLiteral HANDLER_LITERAL = CEntryPointLiteral.create(WindowsSubstrateSegfaultHandler.class, "handler", ErrHandlingAPI.EXCEPTION_POINTERS.class); - @CEntryPoint - @CEntryPointOptions(prologue = NoPrologue.class, epilogue = NoEpilogue.class, publishAs = Publish.SymbolOnly, include = NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = NoPrologue.class, epilogue = NoEpilogue.class, publishAs = Publish.SymbolOnly) @Uninterruptible(reason = "Must be uninterruptible until we get immune to safepoints.") @RestrictHeapAccess(access = NO_HEAP_ACCESS, reason = "We have yet to enter the isolate.") private static int handler(ErrHandlingAPI.EXCEPTION_POINTERS exceptionInfo) { diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSystemPropertiesSupport.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSystemPropertiesSupport.java index 8ae7f86a2845..ae542af21b06 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSystemPropertiesSupport.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSystemPropertiesSupport.java @@ -92,7 +92,7 @@ protected String userNameValue() { @Override protected String userHomeValue() { WinBase.LPHANDLE tokenHandle = StackValue.get(WinBase.LPHANDLE.class); - if (Process.OpenProcessToken(Process.GetCurrentProcess(), Process.TOKEN_QUERY(), tokenHandle) == 0) { + if (Process.NoTransitions.OpenProcessToken(Process.NoTransitions.GetCurrentProcess(), Process.TOKEN_QUERY(), tokenHandle) == 0) { return "C:\\"; // matches openjdk } diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsUtils.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsUtils.java index dab7acd92e7f..66ab86a0a68e 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsUtils.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsUtils.java @@ -61,7 +61,7 @@ private static final class Target_java_lang_ProcessImpl { public static int getpid(java.lang.Process process) { Target_java_lang_ProcessImpl processImpl = SubstrateUtil.cast(process, Target_java_lang_ProcessImpl.class); - return com.oracle.svm.core.windows.headers.Process.GetProcessId(WordFactory.pointer(processImpl.handle)); + return com.oracle.svm.core.windows.headers.Process.NoTransitions.GetProcessId(WordFactory.pointer(processImpl.handle)); } @TargetClass(java.io.FileDescriptor.class) diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMLockSupport.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMLockSupport.java index 49a555f2d534..9774974ca9f2 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMLockSupport.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMLockSupport.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.core.windows; +import static com.oracle.svm.core.annotate.RestrictHeapAccess.Access.NO_ALLOCATION; + import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.word.Word; @@ -38,6 +40,7 @@ import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.annotate.AutomaticFeature; +import com.oracle.svm.core.annotate.RestrictHeapAccess; import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.annotate.UnknownObjectField; import com.oracle.svm.core.config.ConfigurationValues; @@ -47,7 +50,8 @@ import com.oracle.svm.core.locks.VMLockSupport; import com.oracle.svm.core.locks.VMMutex; import com.oracle.svm.core.log.Log; -import com.oracle.svm.core.thread.VMThreads; +import com.oracle.svm.core.stack.StackOverflowCheck; +import com.oracle.svm.core.thread.VMThreads.SafepointBehavior; import com.oracle.svm.core.windows.headers.Process; import com.oracle.svm.core.windows.headers.SynchAPI; import com.oracle.svm.core.windows.headers.WinBase; @@ -147,21 +151,24 @@ public static void initialize() { WindowsVMLockSupport support = WindowsVMLockSupport.singleton(); for (WindowsVMMutex mutex : support.mutexes) { // critical sections on windows always support recursive locking - Process.InitializeCriticalSection(mutex.getStructPointer()); + Process.NoTransitions.InitializeCriticalSection(mutex.getStructPointer()); } for (WindowsVMCondition condition : support.conditions) { - Process.InitializeConditionVariable(condition.getStructPointer()); + Process.NoTransitions.InitializeConditionVariable(condition.getStructPointer()); } } @Uninterruptible(reason = "Called from uninterruptible code.", calleeMustBe = false) + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate in fatal error handling.", overridesCallers = true) static void checkResult(int result, String functionName) { if (result == 0) { /* * Functions are called very early and late during our execution, so there is not much * we can do when they fail. */ - VMThreads.StatusSupport.setStatusIgnoreSafepoints(); + SafepointBehavior.preventSafepoints(); + StackOverflowCheck.singleton().disableStackOverflowChecksForFatalError(); + int lastError = WinBase.GetLastError(); Log.log().string(functionName).string(" failed with error ").hex(lastError).newline(); ImageSingletons.lookup(LogHandler.class).fatalError(); @@ -205,14 +212,14 @@ public VMMutex lock() { @Uninterruptible(reason = "Called from uninterruptible code.", callerMustBe = true) public void lockNoTransition() { assertNotOwner("Recursive locking is not supported"); - Process.EnterCriticalSectionNoTrans(getStructPointer()); + Process.NoTransitions.EnterCriticalSection(getStructPointer()); setOwnerToCurrentThread(); } @Override @Uninterruptible(reason = "Called from uninterruptible code.", callerMustBe = true) public void lockNoTransitionUnspecifiedOwner() { - Process.EnterCriticalSectionNoTrans(getStructPointer()); + Process.NoTransitions.EnterCriticalSection(getStructPointer()); setOwnerToUnspecified(); } @@ -220,20 +227,20 @@ public void lockNoTransitionUnspecifiedOwner() { @Uninterruptible(reason = "Called from uninterruptible code.") public void unlock() { clearCurrentThreadOwner(); - Process.LeaveCriticalSection(getStructPointer()); + Process.NoTransitions.LeaveCriticalSection(getStructPointer()); } @Override @Uninterruptible(reason = "Called from uninterruptible code.") public void unlockNoTransitionUnspecifiedOwner() { clearUnspecifiedOwner(); - Process.LeaveCriticalSection(getStructPointer()); + Process.NoTransitions.LeaveCriticalSection(getStructPointer()); } @Override public void unlockWithoutChecks() { clearCurrentThreadOwner(); - Process.LeaveCriticalSectionNoTrans(getStructPointer()); + Process.NoTransitions.LeaveCriticalSection(getStructPointer()); } } @@ -262,7 +269,7 @@ public void block() { @Uninterruptible(reason = "Called from uninterruptible code.", callerMustBe = true) public void blockNoTransition() { mutex.clearCurrentThreadOwner(); - WindowsVMLockSupport.checkResult(Process.SleepConditionVariableCSNoTrans(getStructPointer(), ((WindowsVMMutex) getMutex()).getStructPointer(), SynchAPI.INFINITE()), + WindowsVMLockSupport.checkResult(Process.NoTransitions.SleepConditionVariableCS(getStructPointer(), ((WindowsVMMutex) getMutex()).getStructPointer(), SynchAPI.INFINITE()), "SleepConditionVariableCS"); mutex.setOwnerToCurrentThread(); } @@ -271,7 +278,7 @@ public void blockNoTransition() { @Uninterruptible(reason = "Called from uninterruptible code.", callerMustBe = true) public void blockNoTransitionUnspecifiedOwner() { mutex.clearUnspecifiedOwner(); - WindowsVMLockSupport.checkResult(Process.SleepConditionVariableCSNoTrans(getStructPointer(), ((WindowsVMMutex) getMutex()).getStructPointer(), SynchAPI.INFINITE()), + WindowsVMLockSupport.checkResult(Process.NoTransitions.SleepConditionVariableCS(getStructPointer(), ((WindowsVMMutex) getMutex()).getStructPointer(), SynchAPI.INFINITE()), "SleepConditionVariableCS"); mutex.setOwnerToUnspecified(); } @@ -308,7 +315,7 @@ public long blockNoTransition(long waitNanos) { int dwMilliseconds = (int) (waitNanos / WindowsUtils.NANOSECS_PER_MILLISEC); mutex.clearCurrentThreadOwner(); - final int timedwaitResult = Process.SleepConditionVariableCSNoTrans(getStructPointer(), ((WindowsVMMutex) getMutex()).getStructPointer(), dwMilliseconds); + final int timedwaitResult = Process.NoTransitions.SleepConditionVariableCS(getStructPointer(), ((WindowsVMMutex) getMutex()).getStructPointer(), dwMilliseconds); mutex.setOwnerToCurrentThread(); /* If the timed wait timed out, then I am done blocking. */ @@ -325,12 +332,12 @@ public long blockNoTransition(long waitNanos) { @Override public void signal() { - Process.WakeConditionVariable(getStructPointer()); + Process.NoTransitions.WakeConditionVariable(getStructPointer()); } @Override @Uninterruptible(reason = "Called from uninterruptible code.") public void broadcast() { - Process.WakeAllConditionVariable(getStructPointer()); + Process.NoTransitions.WakeAllConditionVariable(getStructPointer()); } } diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMThreads.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMThreads.java index bf486e90bc73..d15cc5a6eaaf 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMThreads.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMThreads.java @@ -46,8 +46,8 @@ public final class WindowsVMThreads extends VMThreads { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @Override public OSThreadHandle getCurrentOSThreadHandle() { - WinBase.HANDLE pseudoThreadHandle = Process.GetCurrentThread(); - WinBase.HANDLE pseudoProcessHandle = Process.GetCurrentProcess(); + WinBase.HANDLE pseudoThreadHandle = Process.NoTransitions.GetCurrentThread(); + WinBase.HANDLE pseudoProcessHandle = Process.NoTransitions.GetCurrentProcess(); // convert the thread pseudo handle to a real handle using DuplicateHandle WinBase.LPHANDLE pointerToResult = StackValue.get(WinBase.LPHANDLE.class); @@ -61,7 +61,7 @@ public OSThreadHandle getCurrentOSThreadHandle() { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @Override protected OSThreadId getCurrentOSThreadId() { - return WordFactory.unsigned(Process.GetCurrentThreadId()); + return WordFactory.unsigned(Process.NoTransitions.GetCurrentThreadId()); } @Uninterruptible(reason = "Called from uninterruptible code.") @@ -80,6 +80,17 @@ public void nativeSleep(int milliseconds) { SynchAPI.NoTransitions.Sleep(milliseconds); } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + @Override + public void yield() { + Process.NoTransitions.SwitchToThread(); + } + + @Override + public boolean supportsPatientSafepoints() { + return true; + } + /** * Make sure the runtime is initialized for threading. */ diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/Process.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/Process.java index e46fdb7ecbe1..b21eedc4617a 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/Process.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/Process.java @@ -44,27 +44,9 @@ @CContext(WindowsDirectives.class) public class Process { - @CFunction(transition = Transition.NO_TRANSITION) - public static native HANDLE GetCurrentProcess(); - - @CFunction(transition = Transition.NO_TRANSITION) - public static native HANDLE OpenProcess(int dwDesiredAccess, int bInheritHandle, int dwProcessId); - @CConstant public static native int PROCESS_TERMINATE(); - @CFunction(transition = Transition.NO_TRANSITION) - public static native int TerminateProcess(HANDLE hProcess, int uExitCode); - - @CFunction(transition = Transition.NO_TRANSITION) - public static native int GetCurrentProcessId(); - - @CFunction(transition = Transition.NO_TRANSITION) - public static native int GetProcessId(HANDLE hProcess); - - @CFunction(transition = Transition.NO_TRANSITION) - public static native int OpenProcessToken(HANDLE processHandle, int desiredAccess, LPHANDLE tokenHandle); - @CConstant public static native int TOKEN_QUERY(); @@ -81,18 +63,9 @@ public static native HANDLE _beginthreadex(PointerBase security, int stacksize, @CFunction public static native int ResumeThread(HANDLE hThread); - @CFunction(transition = Transition.NO_TRANSITION) - public static native int GetExitCodeThread(HANDLE hThread, CIntPointer lpExitCode); - @CFunction public static native int SwitchToThread(); - @CFunction(transition = Transition.NO_TRANSITION) - public static native int GetCurrentThreadId(); - - @CFunction(transition = Transition.NO_TRANSITION) - public static native HANDLE GetCurrentThread(); - @CConstant public static native int SYNCHRONIZE(); @@ -104,21 +77,9 @@ public interface PCRITICAL_SECTION extends PointerBase { public interface CRITICAL_SECTION extends PointerBase { } - @CFunction(transition = Transition.NO_TRANSITION) - public static native void InitializeCriticalSection(PCRITICAL_SECTION mutex); - - @CFunction(transition = Transition.TO_NATIVE) + @CFunction public static native void EnterCriticalSection(PCRITICAL_SECTION mutex); - @CFunction(value = "EnterCriticalSection", transition = Transition.NO_TRANSITION) - public static native void EnterCriticalSectionNoTrans(PCRITICAL_SECTION mutex); - - @CFunction(transition = Transition.NO_TRANSITION) - public static native void LeaveCriticalSection(PCRITICAL_SECTION mutex); - - @CFunction(value = "LeaveCriticalSection", transition = Transition.NO_TRANSITION) - public static native void LeaveCriticalSectionNoTrans(PCRITICAL_SECTION mutex); - @CStruct public interface PCONDITION_VARIABLE extends PointerBase { } @@ -127,18 +88,59 @@ public interface PCONDITION_VARIABLE extends PointerBase { public interface CONDITION_VARIABLE extends PointerBase { } - @CFunction(transition = Transition.NO_TRANSITION) - public static native void InitializeConditionVariable(PCONDITION_VARIABLE cond); - @CFunction public static native int SleepConditionVariableCS(PCONDITION_VARIABLE cond, PCRITICAL_SECTION mutex, int dwMilliseconds); - @CFunction(value = "SleepConditionVariableCS", transition = Transition.NO_TRANSITION) - public static native int SleepConditionVariableCSNoTrans(PCONDITION_VARIABLE cond, PCRITICAL_SECTION mutex, int dwMilliseconds); + public static class NoTransitions { + @CFunction(transition = Transition.NO_TRANSITION) + public static native HANDLE GetCurrentProcess(); - @CFunction(transition = Transition.NO_TRANSITION) - public static native void WakeConditionVariable(PCONDITION_VARIABLE cond); + @CFunction(transition = Transition.NO_TRANSITION) + public static native HANDLE OpenProcess(int dwDesiredAccess, int bInheritHandle, int dwProcessId); - @CFunction(transition = Transition.NO_TRANSITION) - public static native void WakeAllConditionVariable(PCONDITION_VARIABLE cond); + @CFunction(transition = Transition.NO_TRANSITION) + public static native int TerminateProcess(HANDLE hProcess, int uExitCode); + + @CFunction(transition = Transition.NO_TRANSITION) + public static native int GetCurrentProcessId(); + + @CFunction(transition = Transition.NO_TRANSITION) + public static native int GetProcessId(HANDLE hProcess); + + @CFunction(transition = Transition.NO_TRANSITION) + public static native int OpenProcessToken(HANDLE processHandle, int desiredAccess, LPHANDLE tokenHandle); + + @CFunction(transition = Transition.NO_TRANSITION) + public static native int GetExitCodeThread(HANDLE hThread, CIntPointer lpExitCode); + + @CFunction(transition = Transition.NO_TRANSITION) + public static native int SwitchToThread(); + + @CFunction(transition = Transition.NO_TRANSITION) + public static native int GetCurrentThreadId(); + + @CFunction(transition = Transition.NO_TRANSITION) + public static native HANDLE GetCurrentThread(); + + @CFunction(transition = Transition.NO_TRANSITION) + public static native void InitializeCriticalSection(PCRITICAL_SECTION mutex); + + @CFunction(transition = Transition.NO_TRANSITION) + public static native void EnterCriticalSection(PCRITICAL_SECTION mutex); + + @CFunction(transition = Transition.NO_TRANSITION) + public static native void LeaveCriticalSection(PCRITICAL_SECTION mutex); + + @CFunction(transition = Transition.NO_TRANSITION) + public static native void InitializeConditionVariable(PCONDITION_VARIABLE cond); + + @CFunction(transition = Transition.NO_TRANSITION) + public static native int SleepConditionVariableCS(PCONDITION_VARIABLE cond, PCRITICAL_SECTION mutex, int dwMilliseconds); + + @CFunction(transition = Transition.NO_TRANSITION) + public static native void WakeConditionVariable(PCONDITION_VARIABLE cond); + + @CFunction(transition = Transition.NO_TRANSITION) + public static native void WakeAllConditionVariable(PCONDITION_VARIABLE cond); + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/HiddenClassSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/BuildPhaseProvider.java similarity index 57% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/HiddenClassSupport.java rename to substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/BuildPhaseProvider.java index 9f3713891e35..ab4441065e87 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/HiddenClassSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/BuildPhaseProvider.java @@ -22,31 +22,42 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk; +package com.oracle.svm.core; -import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; -import com.oracle.svm.core.util.VMError; +@Platforms(Platform.HOSTED_ONLY.class) +public final class BuildPhaseProvider { -/** - * Abstracts the information about hidden classes, which are not available in Java 11 and Java 8. - * This class provides all information about hidden classes without exposing any JDK types and - * methods that are not yet present in the old JDKs. - */ -public abstract class HiddenClassSupport { - @Fold - public static HiddenClassSupport singleton() { - return ImageSingletons.lookup(HiddenClassSupport.class); + private boolean analysisFinished; + private boolean hostedUniverseBuilt; + + public static void init() { + ImageSingletons.add(BuildPhaseProvider.class, new BuildPhaseProvider()); + } + + static BuildPhaseProvider singleton() { + return ImageSingletons.lookup(BuildPhaseProvider.class); + } + + BuildPhaseProvider() { + } + + public static void markAnalysisFinished() { + singleton().analysisFinished = true; + } + + public static boolean isAnalysisFinished() { + return singleton().analysisFinished; } - @Fold - public static boolean isAvailable() { - return ImageSingletons.contains(HiddenClassSupport.class); + public static void markHostedUniverseBuilt() { + singleton().hostedUniverseBuilt = true; } - /** Same as {@code Class.isHidden()}. */ - public boolean isHidden(@SuppressWarnings("unused") Class clazz) { - throw VMError.shouldNotReachHere(); + public static boolean isHostedUniverseBuilt() { + return singleton().hostedUniverseBuilt; } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/Containers.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/Containers.java index f6828743c3dd..1c338ac0fc4d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/Containers.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/Containers.java @@ -44,7 +44,7 @@ /** * Provides container awareness to the rest of the VM. * - * The implementation is based on the Container Metrics API from JDK 15. + * The implementation is based on the Container Metrics API from JDK 17. */ public class Containers { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK11_0_10OrEarlier.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/FunctionPointerHolder.java similarity index 70% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK11_0_10OrEarlier.java rename to substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/FunctionPointerHolder.java index 826e99189c19..365cd0c2df15 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK11_0_10OrEarlier.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/FunctionPointerHolder.java @@ -22,17 +22,20 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk; +package com.oracle.svm.core; -import java.util.function.BooleanSupplier; +import org.graalvm.nativeimage.c.function.CFunctionPointer; -import org.graalvm.compiler.serviceprovider.JavaVersionUtil; -import org.graalvm.compiler.serviceprovider.GraalServices; +/** + * Isolates require that all function pointers to image methods are in immutable classes. This class + * can be used as an immutable indirection for mutable classes that need to store a function + * pointer. + */ +public class FunctionPointerHolder { + + public final CFunctionPointer functionPointer; -public class JDK11_0_10OrEarlier implements BooleanSupplier { - @Override - public boolean getAsBoolean() { - return JavaVersionUtil.JAVA_SPEC < 11 || - (JavaVersionUtil.JAVA_SPEC == 11 && GraalServices.getJavaUpdateVersion() <= 10); + public FunctionPointerHolder(CFunctionPointer functionPointer) { + this.functionPointer = functionPointer; } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/InvalidVTableEntryHandler.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/InvalidMethodPointerHandler.java similarity index 56% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/InvalidVTableEntryHandler.java rename to substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/InvalidMethodPointerHandler.java index 43b7f36d57f5..aaec92b0e0a7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/InvalidVTableEntryHandler.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/InvalidMethodPointerHandler.java @@ -26,6 +26,8 @@ // Checkstyle: allow reflection +import static com.oracle.svm.core.annotate.RestrictHeapAccess.Access.NO_ALLOCATION; + import java.lang.reflect.Method; import org.graalvm.nativeimage.ImageSingletons; @@ -35,25 +37,46 @@ import org.graalvm.word.WordFactory; import com.oracle.svm.core.annotate.NeverInline; +import com.oracle.svm.core.annotate.RestrictHeapAccess; import com.oracle.svm.core.annotate.StubCallingConvention; +import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.snippets.KnownIntrinsics; import com.oracle.svm.core.stack.StackOverflowCheck; -import com.oracle.svm.core.thread.VMThreads; +import com.oracle.svm.core.thread.VMThreads.SafepointBehavior; import com.oracle.svm.util.ReflectionUtil; /** - * Provides a stub method that can be used to fill otherwise unused vtable slots. Instead of a - * segfault, this method provides a full diagnostic output with a stack trace. + * Provides stub methods that can be used for uninitialized method pointers. Instead of a segfault, + * the stubs provide full diagnostic output with a stack trace. */ -public final class InvalidVTableEntryHandler { - public static final Method HANDLER_METHOD = ReflectionUtil.lookupMethod(InvalidVTableEntryHandler.class, "invalidVTableEntryHandler"); - public static final String MSG = "Fatal error: Virtual method call used an illegal vtable entry that was seen as unused by the static analysis"; +public final class InvalidMethodPointerHandler { + public static final Method INVALID_VTABLE_ENTRY_HANDLER_METHOD = ReflectionUtil.lookupMethod(InvalidMethodPointerHandler.class, "invalidVTableEntryHandler"); + public static final String INVALID_VTABLE_ENTRY_MSG = "Fatal error: Virtual method call used an illegal vtable entry that was seen as unused by the static analysis"; + + public static final Method METHOD_POINTER_NOT_COMPILED_HANDLER_METHOD = ReflectionUtil.lookupMethod(InvalidMethodPointerHandler.class, "methodPointerNotCompiledHandler"); + public static final String METHOD_POINTER_NOT_COMPILED_MSG = "Fatal error: Method pointer invoked on a method that was not compiled because it was not seen as invoked by the static analysis nor was it directly registered for compilation"; @StubCallingConvention @NeverInline("We need a separate frame that stores all registers") private static void invalidVTableEntryHandler() { - VMThreads.StatusSupport.setStatusIgnoreSafepoints(); + Pointer callerSP = KnownIntrinsics.readCallerStackPointer(); + CodePointer callerIP = KnownIntrinsics.readReturnAddress(); + failFatally(callerSP, callerIP, INVALID_VTABLE_ENTRY_MSG); + } + + @StubCallingConvention + @NeverInline("We need a separate frame that stores all registers") + private static void methodPointerNotCompiledHandler() { + Pointer callerSP = KnownIntrinsics.readCallerStackPointer(); + CodePointer callerIP = KnownIntrinsics.readReturnAddress(); + failFatally(callerSP, callerIP, METHOD_POINTER_NOT_COMPILED_MSG); + } + + @Uninterruptible(reason = "Prevent safepoints until everything is set up for printing the fatal error.", calleeMustBe = false) + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate in fatal error handling.", overridesCallers = true) + private static void failFatally(Pointer callerSP, CodePointer callerIP, String message) { + SafepointBehavior.preventSafepoints(); StackOverflowCheck.singleton().disableStackOverflowChecksForFatalError(); /* @@ -63,13 +86,11 @@ private static void invalidVTableEntryHandler() { * from the method that has the illegal vtable call. That can be helpful when debugging the * cause of the fatal error. */ - Pointer callerSP = KnownIntrinsics.readCallerStackPointer(); - CodePointer callerIP = KnownIntrinsics.readReturnAddress(); LogHandler logHandler = ImageSingletons.lookup(LogHandler.class); - Log log = Log.enterFatalContext(logHandler, callerIP, MSG, null); + Log log = Log.enterFatalContext(logHandler, callerIP, message, null); if (log != null) { SubstrateDiagnostics.printFatalError(log, callerSP, callerIP, WordFactory.nullPointer(), true); - log.string(MSG).newline(); + log.string(message).newline(); } logHandler.fatalError(); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java index 8a10aa7acef5..21bb27cc087e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java @@ -176,8 +176,8 @@ public static int runCore() { return exitCode; } - @CEntryPoint - @CEntryPointOptions(prologue = EnterCreateIsolateWithCArgumentsPrologue.class, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = EnterCreateIsolateWithCArgumentsPrologue.class) @SuppressWarnings("unused") public static int run(int argc, CCharPointerPointer argv) { return runCore(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index 2ae835b6f177..ff75a4b0c5c6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -29,6 +29,7 @@ import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.core.common.SuppressFBWarnings; +import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.IsolateThread; @@ -73,13 +74,14 @@ import com.oracle.svm.core.thread.VMOperation; import com.oracle.svm.core.thread.VMOperationControl; import com.oracle.svm.core.thread.VMThreads; +import com.oracle.svm.core.thread.VMThreads.SafepointBehavior; import com.oracle.svm.core.threadlocal.FastThreadLocalBytes; import com.oracle.svm.core.threadlocal.FastThreadLocalFactory; import com.oracle.svm.core.threadlocal.VMThreadLocalInfos; import com.oracle.svm.core.util.Counter; public class SubstrateDiagnostics { - private static final FastThreadLocalBytes threadOnlyAttachedForCrashHandler = FastThreadLocalFactory.createBytes(() -> 1); + private static final FastThreadLocalBytes threadOnlyAttachedForCrashHandler = FastThreadLocalFactory.createBytes(() -> 1, "SubstrateDiagnostics.threadOnlyAttachedForCrashHandler"); @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static void setOnlyAttachedForCrashHandler(IsolateThread thread) { @@ -616,9 +618,13 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev log.string("Threads:").indent(true); for (IsolateThread thread = VMThreads.firstThreadUnsafe(); thread.isNonNull(); thread = VMThreads.nextThread(thread)) { log.zhex(thread).spaces(1).string(VMThreads.StatusSupport.getStatusString(thread)); + + int safepointBehavior = SafepointBehavior.getSafepointBehaviorVolatile(thread); + log.string(" (").string(SafepointBehavior.toString(safepointBehavior)).string(")"); + if (allowJavaHeapAccess) { Thread threadObj = JavaThreads.fromVMThread(thread); - log.string(" \"").string(threadObj.getName()).string("\" - ").object(threadObj); + log.string(" \"").string(threadObj.getName()).string("\" - ").zhex(Word.objectToUntrackedPointer(threadObj)); if (threadObj.isDaemon()) { log.string(", daemon"); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateExitHandlerFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateExitHandlerFeature.java index bce7b3801781..a50ba94c0619 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateExitHandlerFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateExitHandlerFeature.java @@ -24,7 +24,6 @@ */ package com.oracle.svm.core; -import org.graalvm.nativeimage.ImageInfo; import org.graalvm.nativeimage.hosted.Feature; import com.oracle.svm.core.annotate.Alias; @@ -36,7 +35,7 @@ public class SubstrateExitHandlerFeature implements Feature { @Override public void beforeAnalysis(BeforeAnalysisAccess access) { - if (SubstrateOptions.InstallExitHandlers.getValue() && ImageInfo.isExecutable()) { + if (SubstrateOptions.InstallExitHandlers.getValue()) { RuntimeSupport.getRuntimeSupport().addStartupHook(new SubstrateExitHandlerStartupHook()); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateGCOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateGCOptions.java index 9f585c3515bd..f5a020d20cf2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateGCOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateGCOptions.java @@ -30,6 +30,7 @@ import org.graalvm.compiler.options.OptionType; import org.graalvm.word.WordFactory; +import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.HeapSizeVerifier; import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.option.RuntimeOptionKey; @@ -59,6 +60,7 @@ public class SubstrateGCOptions { protected void onValueUpdate(EconomicMap, Object> values, Long oldValue, Long newValue) { if (!SubstrateUtil.HOSTED) { HeapSizeVerifier.verifyMinHeapSizeAgainstAddressSpace(WordFactory.unsigned(newValue)); + Heap.getHeap().updateSizeParameters(); } } }; @@ -69,6 +71,7 @@ protected void onValueUpdate(EconomicMap, Object> values, Long oldV protected void onValueUpdate(EconomicMap, Object> values, Long oldValue, Long newValue) { if (!SubstrateUtil.HOSTED) { HeapSizeVerifier.verifyMaxHeapSizeAgainstAddressSpace(WordFactory.unsigned(newValue)); + Heap.getHeap().updateSizeParameters(); } } }; @@ -79,7 +82,11 @@ protected void onValueUpdate(EconomicMap, Object> values, Long oldV protected void onValueUpdate(EconomicMap, Object> values, Long oldValue, Long newValue) { if (!SubstrateUtil.HOSTED) { HeapSizeVerifier.verifyMaxNewSizeAgainstAddressSpace(WordFactory.unsigned(newValue)); + Heap.getHeap().updateSizeParameters(); } } }; + + @Option(help = "The maximum free bytes reserved for allocations, in bytes (0 for automatic according to GC policy).", type = OptionType.User)// + public static final RuntimeOptionKey MaxHeapFree = new RuntimeOptionKey<>(0L); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index cd99fbebf10f..7fe37435932b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -46,6 +46,7 @@ import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; +import org.graalvm.nativeimage.ImageInfo; import org.graalvm.nativeimage.ImageSingletons; import com.oracle.svm.core.deopt.DeoptimizationSupport; @@ -125,14 +126,9 @@ protected void onValueUpdate(EconomicMap, Object> values, Boolean o private static ValueUpdateHandler optimizeValueUpdateHandler; private static ValueUpdateHandler debugInfoValueUpdateHandler = SubstrateOptions::defaultDebugInfoValueUpdateHandler; - @Option(help = "Show available options based on comma-separated option-types (allowed categories: User, Expert, Debug).")// - public static final OptionKey PrintFlags = new OptionKey<>(null); - - @Option(help = "Print extra help, if available, based on comma-separated option names. Pass * to show all options that contain extra help.")// - public static final OptionKey PrintFlagsWithExtraHelp = new OptionKey<>(null); - @Option(help = "Control native-image code optimizations: 0 - no optimizations, 1 - basic optimizations, 2 - aggressive optimizations.", type = OptionType.User)// - public static final HostedOptionKey Optimize = new HostedOptionKey(2) { + // TODO Currently best to disable optimizations. AOTInline and AOTTrivialInline needs to stay activated! + public static final HostedOptionKey Optimize = new HostedOptionKey(0) { @Override protected void onValueUpdate(EconomicMap, Object> values, Integer oldValue, Integer newValue) { SubstrateOptions.IncludeNodeSourcePositions.update(values, newValue < 1); @@ -157,7 +153,8 @@ public static void setDebugInfoValueUpdateHandler(ValueUpdateHandler updateHandl } @Option(help = "Track NodeSourcePositions during runtime-compilation")// - public static final HostedOptionKey IncludeNodeSourcePositions = new HostedOptionKey<>(false); + //TODO Enabled for easier test + public static final HostedOptionKey IncludeNodeSourcePositions = new HostedOptionKey<>(true); @Option(help = "Search path for C libraries passed to the linker (list of comma-separated directories)")// public static final HostedOptionKey CLibraryPath = new HostedOptionKey<>(new LocatableMultiOptionValue.Strings()); @@ -278,7 +275,7 @@ public Boolean getValue(OptionValues values) { * Object and array allocation options. */ @Option(help = "Number of cache lines to load after the array allocation using prefetch instructions.")// - public static final HostedOptionKey AllocatePrefetchLines = new HostedOptionKey<>(3); + public static final HostedOptionKey AllocatePrefetchLines = new HostedOptionKey<>(4); @Option(help = "Number of cache lines to load after the object address using prefetch instructions.")// public static final HostedOptionKey AllocateInstancePrefetchLines = new HostedOptionKey<>(1); @@ -289,6 +286,14 @@ public Boolean getValue(OptionValues values) { @Option(help = "Sets the prefetch instruction to prefetch ahead of the allocation pointer. Possible values are from 0 to 3. The actual instructions behind the values depend on the platform.")// public static final HostedOptionKey AllocatePrefetchInstr = new HostedOptionKey<>(0); + @Option(help = "Sets the size (in bytes) of the prefetch distance for object allocation. " + + "Memory about to be written with the value of new objects is prefetched up to this distance starting from the address of the last allocated object. " + + "Each Java thread has its own allocation point.")// + public static final HostedOptionKey AllocatePrefetchDistance = new HostedOptionKey<>(192); + + @Option(help = "Sets the step size (in bytes) for sequential prefetch instructions.")// + public static final HostedOptionKey AllocatePrefetchStepSize = new HostedOptionKey<>(64); + /* * Isolate tear down options. */ @@ -307,17 +312,6 @@ public static final long getTearDownFailureNanos() { return TearDownFailureNanos.getValue().longValue(); } - /* - * The default value is derived by taking the common value from HotSpot configs. - */ - @Option(help = "Sets the size (in bytes) of the prefetch distance for object allocation. " + - "Memory about to be written with the value of new objects is prefetched up to this distance starting from the address of the last allocated object. " + - "Each Java thread has its own allocation point.")// - public static final HostedOptionKey AllocatePrefetchDistance = new HostedOptionKey<>(256); - - @Option(help = "Sets the step size (in bytes) for sequential prefetch instructions.")// - public static final HostedOptionKey AllocatePrefetchStepSize = new HostedOptionKey<>(16); - @Option(help = "Define the maximum number of stores for which the loop that zeroes out objects is unrolled.")// public static final HostedOptionKey MaxUnrolledObjectZeroingStores = new HostedOptionKey<>(8); @@ -354,6 +348,9 @@ public static final long getTearDownFailureNanos() { @Option(help = "Use callee saved registers to reduce spilling for low-frequency calls to stubs (if callee saved registers are supported by the architecture)")// public static final HostedOptionKey UseCalleeSavedRegisters = new HostedOptionKey<>(true); + @Option(help = "Use compressed frame encoding for frames without local values.", type = OptionType.Expert)// + public static final HostedOptionKey UseCompressedFrameEncodings = new HostedOptionKey<>(true); + @Option(help = "Report error if [:{,}] is discovered during analysis (valid values for UsageKind: InHeap, Allocated, Reachable).", type = OptionType.Debug)// public static final HostedOptionKey ReportAnalysisForbiddenType = new HostedOptionKey<>(new LocatableMultiOptionValue.Strings()); @@ -362,7 +359,7 @@ public static final long getTearDownFailureNanos() { @Override protected void onValueUpdate(EconomicMap, Object> values, String oldValue, String newValue) { if ("llvm".equals(newValue)) { - if (JavaVersionUtil.JAVA_SPEC >= 9) { + if (JavaVersionUtil.JAVA_SPEC >= 11) { /* See GR-14405, https://github.com/oracle/graal/issues/1056 */ GraalOptions.EmitStringSubstitutions.update(values, false); } @@ -425,7 +422,7 @@ public static boolean useLLVMBackend() { public static final HostedOptionKey CheckToolchain = new HostedOptionKey<>(true); @APIOption(name = "install-exit-handlers")// - @Option(help = "Provide java.lang.Terminator exit handlers for executable images", type = User)// + @Option(help = "Provide java.lang.Terminator exit handlers", type = User)// public static final HostedOptionKey InstallExitHandlers = new HostedOptionKey<>(false); @Option(help = "When set to true, the image generator verifies that the image heap does not contain a home directory as a substring", type = User)// @@ -454,7 +451,8 @@ public static int codeAlignment() { @APIOption(name = "-g", fixedValue = "2", customHelp = "generate debugging information")// @Option(help = "Insert debug info into the generated native image or library")// - public static final HostedOptionKey GenerateDebugInfo = new HostedOptionKey(0) { + //TODO Enabled for easier test + public static final HostedOptionKey GenerateDebugInfo = new HostedOptionKey(1) { @Override protected void onValueUpdate(EconomicMap, Object> values, Integer oldValue, Integer newValue) { debugInfoValueUpdateHandler.onValueUpdate(values, oldValue, newValue); @@ -471,6 +469,7 @@ public static void defaultDebugInfoValueUpdateHandler(EconomicMap, } @Option(help = "Search path for source files for Application or GraalVM classes (list of comma-separated directories or jar files)")// + //TODO Needs to be set public static final HostedOptionKey DebugInfoSourceSearchPath = new HostedOptionKey<>(new LocatableMultiOptionValue.Strings()); @Option(help = "Directory under which to create source file cache for Application or GraalVM classes")// @@ -564,6 +563,22 @@ public Boolean getValue(OptionValues values) { } }; + @Option(help = "Enables signal handling", stability = OptionStability.EXPERIMENTAL, type = Expert)// + public static final RuntimeOptionKey EnableSignalHandling = new RuntimeOptionKey(null) { + @Override + public Boolean getValueOrDefault(UnmodifiableEconomicMap, Object> values) { + if (values.containsKey(this)) { + return (Boolean) values.get(this); + } + return ImageInfo.isExecutable(); + } + + @Override + public Boolean getValue(OptionValues values) { + return getValueOrDefault(values.getMap()); + } + }; + @Option(help = "Enable Java Flight Recorder.")// public static final RuntimeOptionKey FlightRecorder = new RuntimeOptionKey<>(false); @@ -620,4 +635,7 @@ protected void onValueUpdate(EconomicMap, Object> values, String ol @APIOption(name = "configure-reflection-metadata")// @Option(help = "Limit method reflection metadata to configuration entries instead of including it for all reachable methods")// public static final HostedOptionKey ConfigureReflectionMetadata = new HostedOptionKey<>(true); + + @Option(help = "Verify type states computed by the static analysis at run time. This is useful when diagnosing problems in the static analysis, but reduces peak performance significantly.", type = Debug)// + public static final HostedOptionKey VerifyTypes = new HostedOptionKey<>(false); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java index 2f5ff9018b2c..36f45f6415e4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java @@ -26,6 +26,7 @@ import static com.oracle.svm.core.annotate.RestrictHeapAccess.Access.NO_ALLOCATION; +import com.oracle.svm.core.thread.VMThreads.SafepointBehavior; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.options.Option; import org.graalvm.nativeimage.CurrentIsolate; @@ -153,7 +154,7 @@ protected static boolean tryEnterIsolate(RegisterDumper.Context context) { @Uninterruptible(reason = "Must be uninterruptible until we get immune to safepoints.", calleeMustBe = false) @RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate in segfault handler.", overridesCallers = true) protected static void dump(PointerBase signalInfo, RegisterDumper.Context context) { - VMThreads.StatusSupport.setStatusIgnoreSafepoints(); + SafepointBehavior.preventSafepoints(); StackOverflowCheck.singleton().disableStackOverflowChecksForFatalError(); dumpInterruptibly(signalInfo, context); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java index 0cb5e35fdeb1..6f49d3678fad 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java @@ -34,11 +34,11 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Member; import java.lang.reflect.Method; -import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.oracle.svm.util.StringUtil; import org.graalvm.compiler.graph.Node.NodeIntrinsic; import org.graalvm.compiler.java.LambdaUtils; import org.graalvm.compiler.nodes.BreakpointNode; @@ -270,31 +270,7 @@ public static String[] split(String value, String separator) { * regular expression. This avoids making regular expression code reachable. */ public static String[] split(String value, String separator, int limit) { - int offset = 0; - int next; - ArrayList list = null; - while ((next = value.indexOf(separator, offset)) != -1) { - if (list == null) { - list = new ArrayList<>(); - } - boolean limited = limit > 0; - if (!limited || list.size() < limit - 1) { - list.add(value.substring(offset, next)); - offset = next + separator.length(); - } else { - break; - } - } - - if (offset == 0) { - /* No match found. */ - return new String[]{value}; - } - - /* Add remaining segment. */ - list.add(value.substring(offset)); - - return list.toArray(new String[list.size()]); + return StringUtil.split(value, separator, limit); } public static String toHex(byte[] data) { @@ -403,10 +379,10 @@ public static String mangleName(String methodName) { return mangled; } - private static final Method isHiddenMethod = JavaVersionUtil.JAVA_SPEC >= 15 ? ReflectionUtil.lookupMethod(Class.class, "isHidden") : null; + private static final Method isHiddenMethod = JavaVersionUtil.JAVA_SPEC >= 17 ? ReflectionUtil.lookupMethod(Class.class, "isHidden") : null; public static boolean isHiddenClass(Class javaClass) { - if (JavaVersionUtil.JAVA_SPEC >= 15) { + if (JavaVersionUtil.JAVA_SPEC >= 17) { try { return (boolean) isHiddenMethod.invoke(javaClass); } catch (IllegalAccessException | InvocationTargetException e) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/CGlobalDataNonConstantRegistry.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/CGlobalDataNonConstantRegistry.java index c6879b5258db..97f95d797859 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/CGlobalDataNonConstantRegistry.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/CGlobalDataNonConstantRegistry.java @@ -24,14 +24,16 @@ */ package com.oracle.svm.core.c; -import com.oracle.svm.core.graal.code.CGlobalDataInfo; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + import org.graalvm.collections.EconomicMap; import org.graalvm.collections.Equivalence; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; +import com.oracle.svm.core.graal.code.CGlobalDataInfo; +import com.oracle.svm.core.util.ImageHeapMap; /* * The following class is a helper registry, that contains only CGlobalDataInfo for @@ -40,11 +42,14 @@ */ public class CGlobalDataNonConstantRegistry { - private final EconomicMap, CGlobalDataInfo> cGlobalDataInfos = EconomicMap.create(Equivalence.IDENTITY); + private final EconomicMap, CGlobalDataInfo> cGlobalDataInfos = ImageHeapMap.create(Equivalence.IDENTITY); @Platforms(Platform.HOSTED_ONLY.class) // private final Lock lock = new ReentrantLock(); + /** + * Invoked at runtime via com.oracle.svm.hosted.c.CGlobalDataFeature#getCGlobalDataInfoMethod. + */ public CGlobalDataInfo getCGlobalDataInfo(CGlobalDataImpl cGlobalData) { return cGlobalDataInfos.get(cGlobalData); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/function/CEntryPointOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/function/CEntryPointOptions.java index 61eaef0a2e63..aebf9b37560b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/function/CEntryPointOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/function/CEntryPointOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,10 +74,18 @@ public String apply(String name) { * * The provided class must have a nullary constructor, which is used to instantiate the class. * Then the supplier function is called on the newly instantiated instance. + * + * @deprecated Use {@link CEntryPoint#include()}. */ + @Deprecated Class include() default CEntryPointOptions.AlwaysIncluded.class; - /** A {@link BooleanSupplier} that always returns {@code true}. */ + /** + * A {@link BooleanSupplier} that always returns {@code true}. + * + * @deprecated Use {@link org.graalvm.nativeimage.c.function.CEntryPoint.AlwaysIncluded}. + */ + @Deprecated class AlwaysIncluded implements BooleanSupplier { @Override public boolean getAsBoolean() { @@ -85,7 +93,13 @@ public boolean getAsBoolean() { } } - /** A {@link BooleanSupplier} that always returns {@code false}. */ + /** + * A {@link BooleanSupplier} that always returns {@code false}. + * + * @deprecated Use + * {@link org.graalvm.nativeimage.c.function.CEntryPoint.NotIncludedAutomatically}. + */ + @Deprecated class NotIncludedAutomatically implements BooleanSupplier { @Override public boolean getAsBoolean() { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/classinitialization/ClassInitializationInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/classinitialization/ClassInitializationInfo.java index 02ca5909cc50..a69c0c4f9bb3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/classinitialization/ClassInitializationInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/classinitialization/ClassInitializationInfo.java @@ -34,6 +34,7 @@ import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.function.CFunctionPointer; +import com.oracle.svm.core.FunctionPointerHolder; import com.oracle.svm.core.annotate.InvokeJavaFunctionPointer; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.jdk.InternalVMMethod; @@ -91,28 +92,11 @@ interface ClassInitializerFunctionPointer extends CFunctionPointer { void invoke(); } - /** - * Isolates require that all function pointers to image methods are in immutable classes. - * {@link ClassInitializationInfo} is mutable, so we use this class as an immutable indirection. - */ - public static class ClassInitializerFunctionPointerHolder { - /** - * We cannot declare the field to have type {@link ClassInitializerFunctionPointer} because - * during image building the field refers to a wrapper object that cannot implement custom - * interfaces. - */ - final CFunctionPointer functionPointer; - - ClassInitializerFunctionPointerHolder(CFunctionPointer functionPointer) { - this.functionPointer = functionPointer; - } - } - /** * Function pointer to the class initializer, or null if the class does not have a class * initializer. */ - private final ClassInitializerFunctionPointerHolder classInitializer; + private final FunctionPointerHolder classInitializer; /** * The current initialization state. @@ -156,7 +140,7 @@ private ClassInitializationInfo(InitState initState) { @Platforms(Platform.HOSTED_ONLY.class) public ClassInitializationInfo(CFunctionPointer classInitializer) { - this.classInitializer = classInitializer == null || classInitializer.isNull() ? null : new ClassInitializerFunctionPointerHolder(classInitializer); + this.classInitializer = classInitializer == null || classInitializer.isNull() ? null : new FunctionPointerHolder(classInitializer); this.initState = InitState.Linked; this.initLock = new ReentrantLock(); this.hasInitializer = classInitializer != null; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java index 27be5a52b763..0ac344d0be9e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java @@ -214,7 +214,6 @@ public static UnsignedWord getNativeMetadataSize(CodeInfo info) { .add(NonmovableArrays.byteSizeOf(impl.getFrameInfoObjectConstants())) .add(NonmovableArrays.byteSizeOf(impl.getFrameInfoSourceClasses())) .add(NonmovableArrays.byteSizeOf(impl.getFrameInfoSourceMethodNames())) - .add(NonmovableArrays.byteSizeOf(impl.getFrameInfoNames())) .add(NonmovableArrays.byteSizeOf(impl.getDeoptimizationStartOffsets())) .add(NonmovableArrays.byteSizeOf(impl.getDeoptimizationEncodings())) .add(NonmovableArrays.byteSizeOf(impl.getDeoptimizationObjectConstants())) @@ -239,21 +238,39 @@ public static CodePointer absoluteIP(CodeInfo info, long relativeIP) { return (CodePointer) ((UnsignedWord) cast(info).getCodeStart()).add(WordFactory.unsigned(relativeIP)); } - public static long initFrameInfoReader(CodeInfo info, CodePointer ip, ReusableTypeReader frameInfoReader) { + public static class FrameInfoState { + public long entryOffset; + public boolean isFirstFrame; + public boolean isDone; + public int firstValue; + + public FrameInfoState() { + reset(); + } + + public void reset() { + entryOffset = -1; + isFirstFrame = true; + isDone = false; + firstValue = -1; + } + } + + public static void initFrameInfoReader(CodeInfo info, CodePointer ip, ReusableTypeReader frameInfoReader, FrameInfoState state) { long entryOffset = CodeInfoDecoder.lookupCodeInfoEntryOffset(info, relativeIP(info, ip)); + state.entryOffset = entryOffset; if (entryOffset >= 0) { if (!CodeInfoDecoder.initFrameInfoReader(info, entryOffset, frameInfoReader)) { - return -1; + state.entryOffset = -1; } } - return entryOffset; } - public static FrameInfoQueryResult nextFrameInfo(CodeInfo info, long entryOffset, ReusableTypeReader frameInfoReader, - FrameInfoDecoder.FrameInfoQueryResultAllocator resultAllocator, ValueInfoAllocator valueInfoAllocator, boolean fetchFirstFrame) { - int entryFlags = CodeInfoDecoder.loadEntryFlags(info, entryOffset); + public static FrameInfoQueryResult nextFrameInfo(CodeInfo info, ReusableTypeReader frameInfoReader, + FrameInfoDecoder.FrameInfoQueryResultAllocator resultAllocator, ValueInfoAllocator valueInfoAllocator, FrameInfoState state) { + int entryFlags = CodeInfoDecoder.loadEntryFlags(info, state.entryOffset); boolean isDeoptEntry = CodeInfoDecoder.extractFI(entryFlags) == CodeInfoDecoder.FI_DEOPT_ENTRY_INDEX_S4; - return FrameInfoDecoder.decodeFrameInfo(isDeoptEntry, frameInfoReader, info, resultAllocator, valueInfoAllocator, fetchFirstFrame); + return FrameInfoDecoder.decodeFrameInfo(isDeoptEntry, frameInfoReader, info, resultAllocator, valueInfoAllocator, state); } @SuppressWarnings("unchecked") @@ -307,12 +324,11 @@ public static void setCodeInfo(CodeInfo info, NonmovableArray index, Nonmo @Uninterruptible(reason = "Nonmovable object arrays are not visible to GC until installed.") public static void setEncodings(CodeInfo info, NonmovableObjectArray objectConstants, - NonmovableObjectArray> sourceClasses, NonmovableObjectArray sourceMethodNames, NonmovableObjectArray names) { + NonmovableObjectArray> sourceClasses, NonmovableObjectArray sourceMethodNames) { CodeInfoImpl impl = cast(info); impl.setFrameInfoObjectConstants(objectConstants); impl.setFrameInfoSourceClasses(sourceClasses); impl.setFrameInfoSourceMethodNames(sourceMethodNames); - impl.setFrameInfoNames(names); if (!SubstrateUtil.HOSTED) { // notify the GC about the frame metadata that is now live Heap.getHeap().getRuntimeCodeInfoGCSupport().registerFrameMetadata(impl); @@ -370,10 +386,6 @@ public static NonmovableObjectArray getFrameInfoSourceMethodNames(CodeIn return cast(info).getFrameInfoSourceMethodNames(); } - public static NonmovableObjectArray getFrameInfoNames(CodeInfo info) { - return cast(info).getFrameInfoNames(); - } - @Uninterruptible(reason = "Called from uninterruptible code", mayBeInlined = true) private static CodeInfoImpl cast(UntetheredCodeInfo info) { assert isValid(info); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoDecoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoDecoder.java index 76f6a232252b..3f511c8a6d40 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoDecoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoDecoder.java @@ -29,8 +29,8 @@ // Checkstyle: stop import java.lang.reflect.Executable; // Checkstyle: resume -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.graalvm.compiler.api.replacements.Fold; @@ -367,7 +367,7 @@ private static FrameInfoQueryResult loadFrameInfo(CodeInfo info, long entryOffse } int frameInfoIndex = NonmovableByteArrayReader.getS4(CodeInfoAccess.getCodeInfoEncodings(info), offsetFI(entryOffset, entryFlags)); return FrameInfoDecoder.decodeFrameInfo(isDeoptEntry, new ReusableTypeReader(CodeInfoAccess.getFrameInfoEncodings(info), frameInfoIndex), info, - FrameInfoDecoder.HeapBasedFrameInfoQueryResultAllocator, FrameInfoDecoder.HeapBasedValueInfoAllocator, true); + FrameInfoDecoder.HeapBasedFrameInfoQueryResultAllocator, FrameInfoDecoder.HeapBasedValueInfoAllocator); } @AlwaysInline("Make IP-lookup loop call free") @@ -568,9 +568,9 @@ public static Executable[] getMethodMetadata(int typeID) { int modifiers = dataReader.getUVInt(); - int paramCount = dataReader.getUVInt(); - Class[] paramTypes = new Class[paramCount]; - for (int j = 0; j < paramCount; ++j) { + int paramTypeCount = dataReader.getUVInt(); + Class[] paramTypes = new Class[paramTypeCount]; + for (int j = 0; j < paramTypeCount; ++j) { int paramTypeIndex = dataReader.getSVInt(); paramTypes[j] = NonmovableArrays.getObject(CodeInfoAccess.getFrameInfoSourceClasses(info), paramTypeIndex); } @@ -606,27 +606,27 @@ public static Executable[] getMethodMetadata(int typeID) { typeAnnotations[j] = (byte) dataReader.getS1(); } - boolean parameterDataPresent = dataReader.getU1() == 1; - String[] parameterNames = null; - int[] parameterModifiers = null; - if (parameterDataPresent) { - int parameterCount = dataReader.getUVInt(); - parameterNames = new String[parameterCount]; - parameterModifiers = new int[parameterCount]; - for (int j = 0; j < paramCount; ++j) { - int parameterNameIndex = dataReader.getSVInt(); - parameterNames[j] = NonmovableArrays.getObject(CodeInfoAccess.getFrameInfoSourceMethodNames(info), parameterNameIndex); - parameterModifiers[j] = dataReader.getS4(); + boolean reflectParameterDataPresent = dataReader.getU1() == 1; + String[] reflectParameterNames = null; + int[] reflectParameterModifiers = null; + if (reflectParameterDataPresent) { + int reflectParameterCount = dataReader.getUVInt(); + reflectParameterNames = new String[reflectParameterCount]; + reflectParameterModifiers = new int[reflectParameterCount]; + for (int j = 0; j < reflectParameterCount; ++j) { + int reflectParameterNameIndex = dataReader.getSVInt(); + reflectParameterNames[j] = NonmovableArrays.getObject(CodeInfoAccess.getFrameInfoSourceMethodNames(info), reflectParameterNameIndex); + reflectParameterModifiers[j] = dataReader.getS4(); } } if (name.equals("")) { assert returnType == void.class; methods[i] = ImageSingletons.lookup(RuntimeReflectionConstructors.class).newConstructor(declaringClass, paramTypes, exceptionTypes, modifiers, signature, - annotations, parameterAnnotations, typeAnnotations, parameterNames, parameterModifiers); + annotations, parameterAnnotations, typeAnnotations, reflectParameterNames, reflectParameterModifiers); } else { methods[i] = ImageSingletons.lookup(RuntimeReflectionConstructors.class).newMethod(declaringClass, name, paramTypes, returnType, exceptionTypes, modifiers, signature, - annotations, parameterAnnotations, null, typeAnnotations, parameterNames, parameterModifiers); + annotations, parameterAnnotations, null, typeAnnotations, reflectParameterNames, reflectParameterModifiers); } } return methods; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoEncoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoEncoder.java index f43f2fe72f06..910ff742cf13 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoEncoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoEncoder.java @@ -116,7 +116,7 @@ private Encoders() { this.objectConstants = FrequencyEncoder.createEqualityEncoder(); this.sourceClasses = FrequencyEncoder.createEqualityEncoder(); this.sourceMethodNames = FrequencyEncoder.createEqualityEncoder(); - if (FrameInfoDecoder.encodeDebugNames() || FrameInfoDecoder.encodeSourceReferences()) { + if (FrameInfoDecoder.encodeSourceReferences()) { this.names = FrequencyEncoder.createEqualityEncoder(); } else { this.names = null; @@ -127,28 +127,22 @@ private void encodeAllAndInstall(CodeInfo target, ReferenceAdjuster adjuster) { JavaConstant[] encodedJavaConstants = objectConstants.encodeAll(new JavaConstant[objectConstants.getLength()]); Class[] sourceClassesArray = null; String[] sourceMethodNamesArray = null; - String[] namesArray = null; - final boolean encodeDebugNames = FrameInfoDecoder.encodeDebugNames(); - if (encodeDebugNames || FrameInfoDecoder.encodeSourceReferences()) { + if (FrameInfoDecoder.encodeSourceReferences()) { sourceClassesArray = sourceClasses.encodeAll(new Class[sourceClasses.getLength()]); sourceMethodNamesArray = sourceMethodNames.encodeAll(new String[sourceMethodNames.getLength()]); } - if (encodeDebugNames) { - namesArray = names.encodeAll(new String[names.getLength()]); - } - install(target, encodedJavaConstants, sourceClassesArray, sourceMethodNamesArray, namesArray, adjuster); + install(target, encodedJavaConstants, sourceClassesArray, sourceMethodNamesArray, adjuster); } @Uninterruptible(reason = "Nonmovable object arrays are not visible to GC until installed in target.") private static void install(CodeInfo target, JavaConstant[] objectConstantsArray, Class[] sourceClassesArray, - String[] sourceMethodNamesArray, String[] namesArray, ReferenceAdjuster adjuster) { + String[] sourceMethodNamesArray, ReferenceAdjuster adjuster) { NonmovableObjectArray frameInfoObjectConstants = adjuster.copyOfObjectConstantArray(objectConstantsArray); NonmovableObjectArray> frameInfoSourceClasses = (sourceClassesArray != null) ? adjuster.copyOfObjectArray(sourceClassesArray) : NonmovableArrays.nullArray(); NonmovableObjectArray frameInfoSourceMethodNames = (sourceMethodNamesArray != null) ? adjuster.copyOfObjectArray(sourceMethodNamesArray) : NonmovableArrays.nullArray(); - NonmovableObjectArray frameInfoNames = (namesArray != null) ? adjuster.copyOfObjectArray(namesArray) : NonmovableArrays.nullArray(); - CodeInfoAccess.setEncodings(target, frameInfoObjectConstants, frameInfoSourceClasses, frameInfoSourceMethodNames, frameInfoNames); + CodeInfoAccess.setEncodings(target, frameInfoObjectConstants, frameInfoSourceClasses, frameInfoSourceMethodNames); } } @@ -334,7 +328,7 @@ private void encodeIPData() { writeSizeEncoding(encodingBuffer, data, entryFlags); writeExceptionOffset(encodingBuffer, data, entryFlags); writeReferenceMapIndex(encodingBuffer, data, entryFlags); - writeDeoptFrameInfo(encodingBuffer, data, entryFlags); + writeEncodedFrameInfo(encodingBuffer, data, entryFlags); } codeInfoIndex = NonmovableArrays.createByteArray(TypeConversion.asU4(indexBuffer.getBytesWritten())); @@ -439,7 +433,7 @@ private static void writeReferenceMapIndex(UnsafeArrayTypeWriter writeBuffer, IP private static int flagsForDeoptFrameInfo(IPData data) { if (data.frameData == null) { return CodeInfoDecoder.FI_NO_DEOPT; - } else if (TypeConversion.isS4(data.frameData.indexInEncodings)) { + } else if (TypeConversion.isS4(data.frameData.encodedFrameInfoIndex)) { if (data.frameData.frame.isDeoptEntry) { return CodeInfoDecoder.FI_DEOPT_ENTRY_INDEX_S4; } else { @@ -450,11 +444,11 @@ private static int flagsForDeoptFrameInfo(IPData data) { } } - private static void writeDeoptFrameInfo(UnsafeArrayTypeWriter writeBuffer, IPData data, int entryFlags) { + private static void writeEncodedFrameInfo(UnsafeArrayTypeWriter writeBuffer, IPData data, int entryFlags) { switch (CodeInfoDecoder.extractFI(entryFlags)) { case CodeInfoDecoder.FI_DEOPT_ENTRY_INDEX_S4: case CodeInfoDecoder.FI_INFO_ONLY_INDEX_S4: - writeBuffer.putS4(data.frameData.indexInEncodings); + writeBuffer.putS4(data.frameData.encodedFrameInfoIndex); break; } } @@ -519,7 +513,7 @@ static void verifyMethod(SharedMethod method, CompilationResult compilation, int private static void verifyFrame(CompilationResult compilation, BytecodeFrame expectedFrame, FrameInfoQueryResult actualFrame, BitSet visitedVirtualObjects) { assert (expectedFrame == null) == (actualFrame == null); - if (expectedFrame == null || !actualFrame.needLocalValues) { + if (expectedFrame == null || !actualFrame.hasLocalValueInfo()) { return; } verifyFrame(compilation, expectedFrame.caller(), actualFrame.getCaller(), visitedVirtualObjects); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoImpl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoImpl.java index a96da5602940..fd3e06607dc3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoImpl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoImpl.java @@ -194,12 +194,6 @@ interface CodeInfoImpl extends CodeInfo { @RawField void setFrameInfoSourceMethodNames(NonmovableObjectArray frameInfoSourceMethodNames); - @RawField - NonmovableObjectArray getFrameInfoNames(); - - @RawField - void setFrameInfoNames(NonmovableObjectArray frameInfoNames); - @RawField int getState(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoOffsets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoOffsets.java index 2f68861169b7..0e5b2a6e03b4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoOffsets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoOffsets.java @@ -59,10 +59,6 @@ public static long frameInfoSourceMethodNames() { return OffsetOf.get(CodeInfoImpl.class, "FrameInfoSourceMethodNames"); } - public static long frameInfoNames() { - return OffsetOf.get(CodeInfoImpl.class, "FrameInfoNames"); - } - public static long deoptimizationObjectConstants() { return OffsetOf.get(CodeInfoImpl.class, "DeoptimizationObjectConstants"); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoTable.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoTable.java index d70629670fc0..ba39aa63e0e5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoTable.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoTable.java @@ -292,6 +292,5 @@ public void afterCompilation(AfterCompilationAccess config) { config.registerAsImmutable(imageInfo.frameInfoObjectConstants); config.registerAsImmutable(imageInfo.frameInfoSourceClasses); config.registerAsImmutable(imageInfo.frameInfoSourceMethodNames); - config.registerAsImmutable(imageInfo.frameInfoNames); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoDecoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoDecoder.java index 5fad47de76dc..ed582a8518f3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoDecoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoDecoder.java @@ -46,11 +46,32 @@ public class FrameInfoDecoder { + protected static final int BCI_SHIFT = 2; + protected static final int DURING_CALL_MASK = 2; + protected static final int RETHROW_EXCEPTION_MASK = 1; + protected static final int NO_CALLER_BCI = -1; protected static final int NO_LOCAL_INFO_BCI = -2; + /** + * Differentiates between compressed and uncompressed frame slices. See + * {@link #isCompressedFrameSlice(int)} for more information. + */ + protected static final int UNCOMPRESSED_FRAME_SLICE_MARKER = -1; + /** + * Value added to source line to guarantee the value is greater than zero. + */ + protected static final int COMPRESSED_SOURCE_LINE_ADDEND = 2; + protected static boolean isFrameInfoMatch(long frameInfoIndex, NonmovableArray frameInfoEncodings, long searchEncodedBci) { NonmovableByteArrayTypeReader readBuffer = new NonmovableByteArrayTypeReader(frameInfoEncodings, frameInfoIndex); + int firstValue = readBuffer.getSVInt(); + if (isCompressedFrameSlice(firstValue)) { + /* Compressed frame slices have no local bci information. */ + return false; + } + + /* Read encoded bci from uncompressed frame slice. */ long actualEncodedBci = readBuffer.getSV(); assert actualEncodedBci != NO_CALLER_BCI; @@ -138,7 +159,82 @@ public void decodeConstant(ValueInfo valueInfo, NonmovableObjectArray frameIn static final HeapBasedValueInfoAllocator HeapBasedValueInfoAllocator = new HeapBasedValueInfoAllocator(); protected static FrameInfoQueryResult decodeFrameInfo(boolean isDeoptEntry, TypeReader readBuffer, CodeInfo info, - FrameInfoQueryResultAllocator resultAllocator, ValueInfoAllocator valueInfoAllocator, boolean fetchFirstFrame) { + FrameInfoQueryResultAllocator resultAllocator, ValueInfoAllocator valueInfoAllocator) { + return decodeFrameInfo(isDeoptEntry, readBuffer, info, resultAllocator, valueInfoAllocator, new CodeInfoAccess.FrameInfoState()); + } + + protected static FrameInfoQueryResult decodeFrameInfo(boolean isDeoptEntry, TypeReader readBuffer, CodeInfo info, + FrameInfoQueryResultAllocator resultAllocator, ValueInfoAllocator valueInfoAllocator, CodeInfoAccess.FrameInfoState state) { + if (state.isFirstFrame) { + state.firstValue = readBuffer.getSVInt(); + } + + FrameInfoQueryResult result; + if (isCompressedFrameSlice(state.firstValue)) { + result = decodeCompressedFrameInfo(isDeoptEntry, readBuffer, info, resultAllocator, state); + } else { + result = decodeUncompressedFrameInfo(isDeoptEntry, readBuffer, info, resultAllocator, valueInfoAllocator, state); + } + state.isFirstFrame = false; + + return result; + } + + /* + * See (FrameInfoEncoder.CompressedFrameInfoEncodingMedata) for more information about the + * compressed encoding format. + */ + private static FrameInfoQueryResult decodeCompressedFrameInfo(boolean isDeoptEntry, TypeReader readBuffer, CodeInfo info, + FrameInfoQueryResultAllocator resultAllocator, CodeInfoAccess.FrameInfoState state) { + FrameInfoQueryResult result = null; + FrameInfoQueryResult prev = null; + + while (!state.isDone) { + FrameInfoQueryResult cur = resultAllocator.newFrameInfoQueryResult(); + if (cur == null) { + return result; + } + + assert encodeSourceReferences(); + cur.encodedBci = NO_LOCAL_INFO_BCI; + cur.isDeoptEntry = isDeoptEntry; + + final int sourceClassIndex; + if (state.isFirstFrame) { + sourceClassIndex = state.firstValue; + } else { + sourceClassIndex = readBuffer.getSVInt(); + assert !isDeoptEntry : "Deoptimization entry must not have inlined frames"; + } + + final int sourceMethodNameIndex = readBuffer.getSVInt(); + final int encodedSourceLineNumber = readBuffer.getSVInt(); + final int sourceLineNumber = decodeCompressedSourceLineNumber(encodedSourceLineNumber); + + cur.sourceClassIndex = sourceClassIndex; + cur.sourceMethodNameIndex = sourceMethodNameIndex; + + cur.sourceClass = NonmovableArrays.getObject(CodeInfoAccess.getFrameInfoSourceClasses(info), sourceClassIndex); + cur.sourceMethodName = NonmovableArrays.getObject(CodeInfoAccess.getFrameInfoSourceMethodNames(info), sourceMethodNameIndex); + cur.sourceLineNumber = sourceLineNumber; + + if (prev == null) { + // first frame read during this invocation + result = cur; + } else { + prev.caller = cur; + } + prev = cur; + + state.isDone = encodedSourceLineNumber < 0; + state.isFirstFrame = false; + } + + return result; + } + + private static FrameInfoQueryResult decodeUncompressedFrameInfo(boolean isDeoptEntry, TypeReader readBuffer, CodeInfo info, + FrameInfoQueryResultAllocator resultAllocator, ValueInfoAllocator valueInfoAllocator, CodeInfoAccess.FrameInfoState state) { FrameInfoQueryResult result = null; FrameInfoQueryResult prev = null; ValueInfo[][] virtualObjects = null; @@ -154,12 +250,12 @@ protected static FrameInfoQueryResult decodeFrameInfo(boolean isDeoptEntry, Type return result; } + assert state.isFirstFrame || !isDeoptEntry : "Deoptimization entry must not have inlined frames"; + cur.encodedBci = encodedBci; cur.isDeoptEntry = isDeoptEntry; final boolean needLocalValues = encodedBci != NO_LOCAL_INFO_BCI; - cur.needLocalValues = needLocalValues; - int curValueInfosLenght = 0; if (needLocalValues) { cur.numLocks = readBuffer.getUVInt(); @@ -181,39 +277,25 @@ protected static FrameInfoQueryResult decodeFrameInfo(boolean isDeoptEntry, Type cur.deoptMethodOffset = deoptMethodIndex; } - curValueInfosLenght = readBuffer.getUVInt(); - cur.valueInfos = decodeValues(valueInfoAllocator, curValueInfosLenght, readBuffer, CodeInfoAccess.getFrameInfoObjectConstants(info)); + int curValueInfosLength = readBuffer.getUVInt(); + cur.valueInfos = decodeValues(valueInfoAllocator, curValueInfosLength, readBuffer, CodeInfoAccess.getFrameInfoObjectConstants(info)); } - if (prev != null) { - prev.caller = cur; - assert !isDeoptEntry : "Deoptimization entry must not have inlined frames"; - } else { - if (!fetchFirstFrame) { - /* CodeInfoDecoder.nextFrameInfo usecase. First frame was fetched previously. */ - result = cur; - } else { - /* This is the first frame, i.e., the top frame that will be returned. */ - result = cur; - - if (needLocalValues) { - int numVirtualObjects = readBuffer.getUVInt(); - virtualObjects = valueInfoAllocator.newValueInfoArrayArray(numVirtualObjects); - for (int i = 0; i < numVirtualObjects; i++) { - int numValues = readBuffer.getUVInt(); - ValueInfo[] decodedValues = decodeValues(valueInfoAllocator, numValues, readBuffer, CodeInfoAccess.getFrameInfoObjectConstants(info)); - if (virtualObjects != null) { - virtualObjects[i] = decodedValues; - } - } + if (state.isFirstFrame && needLocalValues) { + /* This is the first frame, i.e., the top frame that will be returned. */ + int numVirtualObjects = readBuffer.getUVInt(); + virtualObjects = valueInfoAllocator.newValueInfoArrayArray(numVirtualObjects); + for (int i = 0; i < numVirtualObjects; i++) { + int numValues = readBuffer.getUVInt(); + ValueInfo[] decodedValues = decodeValues(valueInfoAllocator, numValues, readBuffer, CodeInfoAccess.getFrameInfoObjectConstants(info)); + if (virtualObjects != null) { + virtualObjects[i] = decodedValues; } } } - prev = cur; cur.virtualObjects = virtualObjects; - final boolean debugNames = needLocalValues && encodeDebugNames(); - if (debugNames || encodeSourceReferences()) { + if (encodeSourceReferences()) { final int sourceClassIndex = readBuffer.getSVInt(); final int sourceMethodNameIndex = readBuffer.getSVInt(); final int sourceLineNumber = readBuffer.getSVInt(); @@ -226,15 +308,15 @@ protected static FrameInfoQueryResult decodeFrameInfo(boolean isDeoptEntry, Type cur.sourceLineNumber = sourceLineNumber; } - if (debugNames) { - for (int i = 0; i < curValueInfosLenght; ++i) { - int nameIndex = readBuffer.getUVInt(); - if (cur.valueInfos != null) { - cur.valueInfos[i].nameIndex = nameIndex; - cur.valueInfos[i].name = NonmovableArrays.getObject(CodeInfoAccess.getFrameInfoNames(info), nameIndex); - } - } + if (prev == null) { + // first frame read during this invocation + result = cur; + } else { + prev.caller = cur; } + prev = cur; + + state.isFirstFrame = false; } } @@ -267,18 +349,10 @@ private static ValueInfo[] decodeValues(ValueInfoAllocator valueInfoAllocator, i return valueInfos; } - protected static boolean encodeDebugNames() { - return false; - } - protected static boolean encodeSourceReferences() { return SubstrateOptions.StackTrace.getValue(); } - protected static final int BCI_SHIFT = 2; - protected static final int DURING_CALL_MASK = 2; - protected static final int RETHROW_EXCEPTION_MASK = 1; - protected static int decodeBci(long encodedBci) { return TypeConversion.asS4(encodedBci >> BCI_SHIFT); } @@ -291,6 +365,21 @@ protected static boolean decodeRethrowException(long encodedBci) { return (encodedBci & RETHROW_EXCEPTION_MASK) != 0; } + /** + * Complement of (FrameInfoEncode.encodeCompressedSourceLineNumber). + */ + private static int decodeCompressedSourceLineNumber(int sourceLineNumber) { + return Math.abs(sourceLineNumber) - COMPRESSED_SOURCE_LINE_ADDEND; + } + + /** + * Differentiates between compressed and uncompressed frame slice. Uncompressed frame slices are + * start with an {@link #UNCOMPRESSED_FRAME_SLICE_MARKER}. + */ + private static boolean isCompressedFrameSlice(int firstValue) { + return firstValue != UNCOMPRESSED_FRAME_SLICE_MARKER; + } + public static String readableBci(long encodedBci) { return decodeBci(encodedBci) + ((encodedBci & DURING_CALL_MASK) != 0 ? " duringCall" : "") + diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoEncoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoEncoder.java index cc5eb40a8a18..b52495a6e016 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoEncoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoEncoder.java @@ -29,13 +29,17 @@ import java.util.List; import java.util.Objects; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.util.FrequencyEncoder; import org.graalvm.compiler.core.common.util.TypeConversion; import org.graalvm.compiler.core.common.util.UnsafeArrayTypeWriter; import org.graalvm.nativeimage.ImageSingletons; import com.oracle.svm.core.CalleeSavedRegisters; import com.oracle.svm.core.ReservedRegisters; +import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.c.NonmovableArray; import com.oracle.svm.core.c.NonmovableArrays; @@ -66,26 +70,23 @@ import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaValue; -import jdk.vm.ci.meta.Local; -import jdk.vm.ci.meta.LocalVariableTable; import jdk.vm.ci.meta.ResolvedJavaMethod; public class FrameInfoEncoder { public abstract static class Customization { - protected boolean shouldStoreMethod() { - return true; - } + /** + * Returns true if the method's deoptimization target should be saved within the debugInfo. + */ + protected abstract boolean storeDeoptTargetMethod(); /** - * Returns true if the given debugInfo should be encoded. + * Returns true if the given local values should be encoded within the debugInfo. * * @param method The method that contains the debugInfo. * @param infopoint The infopoint whose debugInfo that is considered for inclusion. */ - protected boolean shouldInclude(ResolvedJavaMethod method, Infopoint infopoint) { - return true; - } + protected abstract boolean includeLocalValues(ResolvedJavaMethod method, Infopoint infopoint); /** * Returns true if the given debugInfo is a valid entry point for deoptimization (and not @@ -94,21 +95,19 @@ protected boolean shouldInclude(ResolvedJavaMethod method, Infopoint infopoint) * @param method The method that contains the debugInfo. * @param infopoint The infopoint whose debugInfo that is considered for inclusion. */ - protected boolean isDeoptEntry(ResolvedJavaMethod method, Infopoint infopoint) { - return false; - } + protected abstract boolean isDeoptEntry(ResolvedJavaMethod method, Infopoint infopoint); /** - * Fills the FrameInfoQueryResult.source* and {@link ValueInfo#name} fields. + * Fills the FrameInfoQueryResult.source* fields. */ - protected abstract void fillDebugNames(BytecodeFrame bytecodeFrame, FrameInfoQueryResult resultFrameInfo, boolean fillValueNames); + protected abstract void fillSourceFields(BytecodeFrame bytecodeFrame, FrameInfoQueryResult resultFrameInfo); } - public abstract static class NamesFromMethod extends Customization { + public abstract static class SourceFieldsFromMethod extends Customization { private final HostedStringDeduplication stringTable = HostedStringDeduplication.singleton(); @Override - protected void fillDebugNames(BytecodeFrame bytecodeFrame, FrameInfoQueryResult resultFrameInfo, boolean fillValueNames) { + protected void fillSourceFields(BytecodeFrame bytecodeFrame, FrameInfoQueryResult resultFrameInfo) { final ResolvedJavaMethod method = bytecodeFrame.getMethod(); final StackTraceElement source = method.asStackTraceElement(bytecodeFrame.getBCI()); @@ -120,30 +119,14 @@ protected void fillDebugNames(BytecodeFrame bytecodeFrame, FrameInfoQueryResult */ resultFrameInfo.sourceMethodName = stringTable.deduplicate(source.getMethodName(), true); resultFrameInfo.sourceLineNumber = source.getLineNumber(); - - if (fillValueNames) { - final LocalVariableTable localVariableTable = bytecodeFrame.getMethod().getLocalVariableTable(); - if (localVariableTable != null) { - Local[] locals = localVariableTable.getLocalsAt(bytecodeFrame.getBCI()); - if (locals != null) { - for (Local local : locals) { - if (local.getSlot() < resultFrameInfo.valueInfos.length) { - resultFrameInfo.valueInfos[local.getSlot()].name = local.getName(); - } else { - assert ValueUtil.isIllegalJavaValue(bytecodeFrame.values[local.getSlot()]); - } - } - } - } - } } protected abstract Class getDeclaringJavaClass(ResolvedJavaMethod method); } - public static class NamesFromImage extends Customization { + public abstract static class SourceFieldsFromImage extends Customization { @Override - protected void fillDebugNames(BytecodeFrame bytecodeFrame, FrameInfoQueryResult resultFrameInfo, boolean fillValueNames) { + protected void fillSourceFields(BytecodeFrame bytecodeFrame, FrameInfoQueryResult resultFrameInfo) { final int deoptOffsetInImage = ((SharedMethod) bytecodeFrame.getMethod()).getDeoptOffsetInImage(); if (deoptOffsetInImage != 0) { CodeInfoQueryResult targetCodeInfo = CodeInfoTable.lookupDeoptimizationEntrypoint(deoptOffsetInImage, resultFrameInfo.encodedBci); @@ -154,41 +137,180 @@ protected void fillDebugNames(BytecodeFrame bytecodeFrame, FrameInfoQueryResult resultFrameInfo.sourceClass = targetFrameInfo.sourceClass; resultFrameInfo.sourceMethodName = targetFrameInfo.sourceMethodName; resultFrameInfo.sourceLineNumber = targetFrameInfo.sourceLineNumber; - - if (fillValueNames) { - final int minLength = Math.min(resultFrameInfo.valueInfos.length, targetFrameInfo.valueInfos.length); - for (int i = 0; i < minLength; i++) { - resultFrameInfo.valueInfos[i].name = targetFrameInfo.valueInfos[i].name; - } - } } } } } + private static final int UNCOMPRESSED_FRAME_SLICE_INDEX = -1; + static class FrameData { protected DebugInfo debugInfo; protected int totalFrameSize; protected ValueInfo[][] virtualObjects; protected FrameInfoQueryResult frame; - protected long indexInEncodings; + protected long encodedFrameInfoIndex; + protected int frameSliceIndex = UNCOMPRESSED_FRAME_SLICE_INDEX; + } + + private static class SourceFieldData { + final Class sourceClass; + final String sourceMethodName; + final int sourceLineNumber; + final boolean isSliceEnd; + + SourceFieldData(Class sourceClass, String sourceMethodName, int sourceLineNumber, boolean isSliceEnd) { + this.sourceClass = sourceClass; + this.sourceMethodName = sourceMethodName; + this.sourceLineNumber = sourceLineNumber; + this.isSliceEnd = isSliceEnd; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SourceFieldData that = (SourceFieldData) o; + return sourceLineNumber == that.sourceLineNumber && isSliceEnd == that.isSliceEnd && sourceClass.equals(that.sourceClass) && sourceMethodName.equals(that.sourceMethodName); + } + + @Override + public int hashCode() { + return Objects.hash(sourceClass, sourceMethodName, sourceLineNumber, isSliceEnd); + } + } + + /** + * When the local values are not needed to be saved within the frame encoding, there can be + * significant space savings via using an alternative encoding. + * + * Within the "compressed" encoding, only the following three values are saved for each frame: + *
      + *
    1. index to source class
    2. + *
    3. index to method name
    4. + *
    5. source line number
    6. + *
    + * + * Due to inlining, multiple frames may represent a given {@link Infopoint}. Hence, for each + * Infopoint, we call the frame(s) representing it a *frame slice*. During decoding, within the + * compressed encoding the last frame of a given frame slice is indicated by reading a negative + * source line number. + * + * Additional space is saved when multiple Infopoints' frame slices are identical. All + * Infopoints with identical frame slice information will point to the same compressed frame + * encoding. + * + * Within the encoded frame metadata, frame slices stored in both the compressed and the + * original (i.e., *uncompressed*) frame encoding can coexist. To differentiate between + * compressed and uncompressed frame slices, uncompressed frame slices start with the + * {@link FrameInfoDecoder#UNCOMPRESSED_FRAME_SLICE_MARKER}. + */ + private static class CompressedFrameInfoEncodingMetadata { + final List framesToEncode = new ArrayList<>(); + final EconomicMap framesToEncodeIndexMap = EconomicMap.create(Equivalence.DEFAULT); + final List> frameSlices = new ArrayList<>(); + final EconomicMap, Integer> frameSliceIndexMap = EconomicMap.create(Equivalence.DEFAULT); + final FrequencyEncoder sliceFrequency = FrequencyEncoder.createEqualityEncoder(); + + boolean sealed = false; + EconomicMap encodedSliceIndexMap = EconomicMap.create(Equivalence.DEFAULT); + + void addFrameSlice(FrameData data, List slice) { + assert !sealed; + List encodedFrameSlice = new ArrayList<>(); + for (SourceFieldData fieldData : slice) { + Integer fieldDataIndex = framesToEncodeIndexMap.get(fieldData); + if (fieldDataIndex == null) { + fieldDataIndex = framesToEncode.size(); + framesToEncode.add(fieldData); + framesToEncodeIndexMap.put(fieldData, fieldDataIndex); + } + encodedFrameSlice.add(framesToEncode.get(fieldDataIndex)); + } + Integer frameSliceIndex = frameSliceIndexMap.get(encodedFrameSlice); + if (frameSliceIndex == null) { + frameSliceIndex = frameSlices.size(); + frameSlices.add(encodedFrameSlice); + frameSliceIndexMap.put(encodedFrameSlice, frameSliceIndex); + } + data.frameSliceIndex = frameSliceIndex; + sliceFrequency.addObject(frameSliceIndex); + } + + void encodeCompressedData(UnsafeArrayTypeWriter encodingBuffer, Encoders encoders) { + assert !sealed; + sealed = true; + Integer[] sliceOrder = sliceFrequency.encodeAll(new Integer[sliceFrequency.getLength()]); + for (Integer sliceIdx : sliceOrder) { + assert !encodedSliceIndexMap.containsKey(sliceIdx); + encodedSliceIndexMap.put(sliceIdx, encodingBuffer.getBytesWritten()); + + List slice = frameSlices.get(sliceIdx); + for (SourceFieldData fieldData : slice) { + int classIndex = encoders.sourceClasses.getIndex(fieldData.sourceClass); + int methodIndex = encoders.sourceMethodNames.getIndex(fieldData.sourceMethodName); + + VMError.guarantee(classIndex != FrameInfoDecoder.UNCOMPRESSED_FRAME_SLICE_MARKER); + + encodingBuffer.putSV(classIndex); + encodingBuffer.putSV(methodIndex); + encodingBuffer.putSV(encodeCompressedSourceLineNumber(fieldData.sourceLineNumber, fieldData.isSliceEnd)); + } + } + } + + long getEncodingOffset(int sliceIndex) { + assert sealed; + Long encodedSliceIndex = encodedSliceIndexMap.get(sliceIndex); + assert encodedSliceIndex != null; + return encodedSliceIndex; + } + + /** + * When verifying the frame encoding, sourceClassIndex and sourceMethodNameIndex must be + * filled in correctly. + */ + boolean writeFrameVerificationInfo(FrameData data, Encoders encoders) { + int curIdx = 0; + List slice = frameSlices.get(data.frameSliceIndex); + for (FrameInfoQueryResult cur = data.frame; cur != null; cur = cur.caller) { + cur.encodedBci = FrameInfoDecoder.NO_LOCAL_INFO_BCI; + assert cur == data.frame || !cur.isDeoptEntry : "Deoptimization entry information for caller frames is not persisted"; + + cur.sourceClassIndex = encoders.sourceClasses.getIndex(cur.sourceClass); + cur.sourceMethodNameIndex = encoders.sourceMethodNames.getIndex(cur.sourceMethodName); + boolean isSliceEnd = cur.caller == null; + SourceFieldData fieldData = new SourceFieldData(cur.sourceClass, cur.sourceMethodName, cur.sourceLineNumber, isSliceEnd); + assert fieldData.equals(slice.get(curIdx)); + curIdx++; + } + assert frameSlices.get(data.frameSliceIndex).size() == curIdx; + return true; + } } private final Customization customization; private final List allDebugInfos; private final Encoders encoders; + private final CompressedFrameInfoEncodingMetadata frameMetadata; protected FrameInfoEncoder(Customization customization, Encoders encoders) { this.customization = customization; this.encoders = encoders; this.allDebugInfos = new ArrayList<>(); + this.frameMetadata = new CompressedFrameInfoEncodingMetadata(); } protected FrameData addDebugInfo(ResolvedJavaMethod method, Infopoint infopoint, int totalFrameSize) { - final boolean shouldIncludeMethod = customization.shouldInclude(method, infopoint); + final boolean includeLocalValues = customization.includeLocalValues(method, infopoint); final boolean encodeSourceReferences = FrameInfoDecoder.encodeSourceReferences(); - if (!shouldIncludeMethod && !encodeSourceReferences) { + final boolean useCompressedEncoding = SubstrateOptions.UseCompressedFrameEncodings.getValue() && !includeLocalValues; + if (!includeLocalValues && !encodeSourceReferences) { return null; } @@ -197,28 +319,34 @@ protected FrameData addDebugInfo(ResolvedJavaMethod method, Infopoint infopoint, data.debugInfo = debugInfo; data.totalFrameSize = totalFrameSize; data.virtualObjects = new ValueInfo[countVirtualObjects(debugInfo)][]; - data.frame = addFrame(data, debugInfo.frame(), customization.isDeoptEntry(method, infopoint), shouldIncludeMethod); + data.frame = addFrame(data, debugInfo.frame(), customization.isDeoptEntry(method, infopoint), includeLocalValues); - final boolean encodeDebugNames = shouldIncludeMethod && FrameInfoDecoder.encodeDebugNames(); - if (encodeDebugNames || FrameInfoDecoder.encodeSourceReferences()) { + if (encodeSourceReferences) { + List frameSlice = useCompressedEncoding ? new ArrayList<>() : null; BytecodeFrame bytecodeFrame = data.debugInfo.frame(); - for (FrameInfoQueryResult resultFrame = data.frame; bytecodeFrame != null; resultFrame = resultFrame.caller) { - customization.fillDebugNames(bytecodeFrame, resultFrame, encodeDebugNames && shouldIncludeMethod); + for (FrameInfoQueryResult resultFrame = data.frame; resultFrame != null; resultFrame = resultFrame.caller) { + assert bytecodeFrame != null; + customization.fillSourceFields(bytecodeFrame, resultFrame); + + // save source class and method name + final Class sourceClass = resultFrame.sourceClass; + final String sourceMethodName = resultFrame.sourceMethodName; + encoders.sourceClasses.addObject(sourceClass); + encoders.sourceMethodNames.addObject(sourceMethodName); + + // save encoding metadata + if (useCompressedEncoding) { + assert !resultFrame.hasLocalValueInfo(); + final boolean isSliceEnd = resultFrame.caller == null; + final int sourceLineNumber = resultFrame.sourceLineNumber; + SourceFieldData fieldData = new SourceFieldData(sourceClass, sourceMethodName, sourceLineNumber, isSliceEnd); + frameSlice.add(fieldData); + } + bytecodeFrame = bytecodeFrame.caller(); } - - for (FrameInfoQueryResult cur = data.frame; cur != null; cur = cur.caller) { - encoders.sourceClasses.addObject(cur.sourceClass); - encoders.sourceMethodNames.addObject(cur.sourceMethodName); - - if (encodeDebugNames) { - for (ValueInfo valueInfo : cur.valueInfos) { - if (valueInfo.name == null) { - valueInfo.name = ""; - } - encoders.names.addObject(valueInfo.name); - } - } + if (useCompressedEncoding) { + frameMetadata.addFrameSlice(data, frameSlice); } } @@ -260,21 +388,20 @@ private FrameInfoQueryResult addFrame(FrameData data, BytecodeFrame frame, boole result.virtualObjects = data.virtualObjects; result.encodedBci = encodeBci(frame.getBCI(), frame.duringCall, frame.rethrowException); result.isDeoptEntry = isDeoptEntry; - result.needLocalValues = needLocalValues; - - SharedMethod method = (SharedMethod) frame.getMethod(); - if (customization.shouldStoreMethod()) { - result.deoptMethod = method; - encoders.objectConstants.addObject(SubstrateObjectConstant.forObject(method)); - } - result.deoptMethodOffset = method.getDeoptOffsetInImage(); - - result.numLocals = frame.numLocals; - result.numStack = frame.numStack; - result.numLocks = frame.numLocks; ValueInfo[] valueInfos = null; if (needLocalValues) { + SharedMethod method = (SharedMethod) frame.getMethod(); + if (customization.storeDeoptTargetMethod()) { + result.deoptMethod = method; + encoders.objectConstants.addObject(SubstrateObjectConstant.forObject(method)); + } + result.deoptMethodOffset = method.getDeoptOffsetInImage(); + + result.numLocals = frame.numLocals; + result.numStack = frame.numStack; + result.numLocks = frame.numLocks; + JavaValue[] values = frame.values; int numValues = 0; for (int i = values.length; --i >= 0;) { @@ -581,19 +708,27 @@ private static void afterInstallation(CodeInfo info) { private NonmovableArray encodeFrameDatas() { UnsafeArrayTypeWriter encodingBuffer = UnsafeArrayTypeWriter.create(ByteArrayReader.supportsUnalignedMemoryAccess()); + frameMetadata.encodeCompressedData(encodingBuffer, encoders); for (FrameData data : allDebugInfos) { - data.indexInEncodings = encodingBuffer.getBytesWritten(); - encodeFrameData(data, encodingBuffer); + if (data.frameSliceIndex == UNCOMPRESSED_FRAME_SLICE_INDEX) { + data.encodedFrameInfoIndex = encodingBuffer.getBytesWritten(); + encodeUncompressedFrameData(data, encodingBuffer); + } else { + data.encodedFrameInfoIndex = frameMetadata.getEncodingOffset(data.frameSliceIndex); + assert frameMetadata.writeFrameVerificationInfo(data, encoders); + } } NonmovableArray frameInfoEncodings = NonmovableArrays.createByteArray(TypeConversion.asS4(encodingBuffer.getBytesWritten())); encodingBuffer.toByteBuffer(NonmovableArrays.asByteBuffer(frameInfoEncodings)); return frameInfoEncodings; } - private void encodeFrameData(FrameData data, UnsafeArrayTypeWriter encodingBuffer) { + private void encodeUncompressedFrameData(FrameData data, UnsafeArrayTypeWriter encodingBuffer) { + encodingBuffer.putSV(FrameInfoDecoder.UNCOMPRESSED_FRAME_SLICE_MARKER); + for (FrameInfoQueryResult cur = data.frame; cur != null; cur = cur.caller) { assert cur.encodedBci != FrameInfoDecoder.NO_CALLER_BCI : "used as the end marker during decoding"; - final boolean needLocalValues = cur.needLocalValues; + final boolean needLocalValues = cur.hasLocalValueInfo(); if (!needLocalValues) { cur.encodedBci = FrameInfoDecoder.NO_LOCAL_INFO_BCI; } @@ -627,8 +762,7 @@ private void encodeFrameData(FrameData data, UnsafeArrayTypeWriter encodingBuffe } } - final boolean encodeDebugNames = needLocalValues && FrameInfoDecoder.encodeDebugNames(); - if (encodeDebugNames || FrameInfoDecoder.encodeSourceReferences()) { + if (FrameInfoDecoder.encodeSourceReferences()) { final int classIndex = encoders.sourceClasses.getIndex(cur.sourceClass); final int methodIndex = encoders.sourceMethodNames.getIndex(cur.sourceMethodName); @@ -639,13 +773,6 @@ private void encodeFrameData(FrameData data, UnsafeArrayTypeWriter encodingBuffe encodingBuffer.putSV(methodIndex); encodingBuffer.putSV(cur.sourceLineNumber); } - - if (encodeDebugNames) { - for (ValueInfo valueInfo : cur.valueInfos) { - valueInfo.nameIndex = encoders.names.getIndex(valueInfo.name); - encodingBuffer.putUV(valueInfo.nameIndex); - } - } } encodingBuffer.putSV(FrameInfoDecoder.NO_CALLER_BCI); } @@ -695,11 +822,21 @@ public static long encodeBci(int bci, boolean duringCall, boolean rethrowExcepti return (((long) bci) << FrameInfoDecoder.BCI_SHIFT) | (duringCall ? FrameInfoDecoder.DURING_CALL_MASK : 0) | (rethrowException ? FrameInfoDecoder.RETHROW_EXCEPTION_MASK : 0); } + /** + * The source line number also encodes whether the is it the end of or a frame slice or not. The + * original value is incremented to guarantee all source line numbers are greater than 0. + */ + private static int encodeCompressedSourceLineNumber(int sourceLineNumber, boolean isSliceEnd) { + int lineNumberWithAddend = sourceLineNumber + FrameInfoDecoder.COMPRESSED_SOURCE_LINE_ADDEND; + VMError.guarantee(lineNumberWithAddend > 0); + return isSliceEnd ? -(lineNumberWithAddend) : (lineNumberWithAddend); + } + void verifyEncoding(CodeInfo info) { for (FrameData expectedData : allDebugInfos) { FrameInfoQueryResult actualFrame = FrameInfoDecoder.decodeFrameInfo(expectedData.frame.isDeoptEntry, - new ReusableTypeReader(CodeInfoAccess.getFrameInfoEncodings(info), expectedData.indexInEncodings), - info, FrameInfoDecoder.HeapBasedFrameInfoQueryResultAllocator, FrameInfoDecoder.HeapBasedValueInfoAllocator, true); + new ReusableTypeReader(CodeInfoAccess.getFrameInfoEncodings(info), expectedData.encodedFrameInfoIndex), + info, FrameInfoDecoder.HeapBasedFrameInfoQueryResultAllocator, FrameInfoDecoder.HeapBasedValueInfoAllocator); FrameInfoVerifier.verifyFrames(expectedData, expectedData.frame, actualFrame); } } @@ -712,8 +849,8 @@ protected static void verifyFrames(FrameInfoEncoder.FrameData expectedData, Fram while (expectedFrame != null) { assert actualFrame != null; assert expectedFrame.isDeoptEntry == actualFrame.isDeoptEntry; - assert expectedFrame.needLocalValues == actualFrame.needLocalValues; - if (expectedFrame.needLocalValues) { + assert expectedFrame.hasLocalValueInfo() == actualFrame.hasLocalValueInfo(); + if (expectedFrame.hasLocalValueInfo()) { assert expectedFrame.encodedBci == actualFrame.encodedBci; assert expectedFrame.deoptMethod == null && actualFrame.deoptMethod == null || ((expectedFrame.deoptMethod != null) && expectedFrame.deoptMethod.equals(actualFrame.deoptMethod)); @@ -739,7 +876,7 @@ protected static void verifyFrames(FrameInfoEncoder.FrameData expectedData, Fram } assert actualFrame == null; - if (actualTopFrame.needLocalValues) { + if (actualTopFrame.hasLocalValueInfo()) { assert expectedData.virtualObjects.length == actualTopFrame.virtualObjects.length; for (int i = 0; i < expectedData.virtualObjects.length; i++) { verifyValues(expectedData.virtualObjects[i], actualTopFrame.virtualObjects[i]); @@ -759,8 +896,6 @@ private static void verifyValues(ValueInfo[] expectedValues, ValueInfo[] actualV assert expectedValue.isEliminatedMonitor == actualValue.isEliminatedMonitor; assert expectedValue.data == actualValue.data; verifyConstant(expectedValue.value, actualValue.value); - assert Objects.equals(expectedValue.name, actualValue.name); - assert expectedValue.nameIndex == actualValue.nameIndex; } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoQueryResult.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoQueryResult.java index 0c71ad083135..9d9a0a1fd920 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoQueryResult.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoQueryResult.java @@ -99,9 +99,6 @@ public static class ValueInfo { protected boolean isEliminatedMonitor; protected long data; protected JavaConstant value; - protected String name; - /** Index of {@link #name} in {@link FrameInfoDecoder#decodeFrameInfo frameInfoNames}. */ - protected int nameIndex = -1; /** * Returns the type of the value, describing how to access the value. @@ -156,7 +153,6 @@ public JavaConstant getValue() { protected int deoptMethodOffset; protected long encodedBci; protected boolean isDeoptEntry; - protected boolean needLocalValues; protected int numLocals; protected int numStack; protected int numLocks; @@ -182,7 +178,6 @@ public void init() { deoptMethodOffset = 0; encodedBci = 0; isDeoptEntry = false; - needLocalValues = false; numLocals = 0; numStack = 0; numLocks = 0; @@ -287,6 +282,13 @@ public int getNumStack() { return numStack; } + /** + * Returns whether any local value info is present. + */ + public boolean hasLocalValueInfo() { + return valueInfos != null; + } + /** * Returns the local variables and expression stack values. */ @@ -370,11 +372,4 @@ public Log log(Log log) { return log; } - - /** - * Returns the name of the local variable with the given index, for debugging purposes only. - */ - public String getLocalVariableName(int idx) { - return idx < valueInfos.length ? valueInfos[idx].name : null; - } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/ImageCodeInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/ImageCodeInfo.java index 2d1f91c9bb65..cd7c4bfda8f6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/ImageCodeInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/ImageCodeInfo.java @@ -65,7 +65,6 @@ public class ImageCodeInfo { @UnknownObjectField(types = {Object[].class}) Object[] frameInfoObjectConstants; @UnknownObjectField(types = {Class[].class}) Class[] frameInfoSourceClasses; @UnknownObjectField(types = {String[].class}) String[] frameInfoSourceMethodNames; - @UnknownObjectField(types = {String[].class}) String[] frameInfoNames; @Platforms(Platform.HOSTED_ONLY.class) ImageCodeInfo() { @@ -98,7 +97,6 @@ CodeInfo prepareCodeInfo() { info.setFrameInfoObjectConstants(NonmovableArrays.fromImageHeap(frameInfoObjectConstants)); info.setFrameInfoSourceClasses(NonmovableArrays.fromImageHeap(frameInfoSourceClasses)); info.setFrameInfoSourceMethodNames(NonmovableArrays.fromImageHeap(frameInfoSourceMethodNames)); - info.setFrameInfoNames(NonmovableArrays.fromImageHeap(frameInfoNames)); return info; } @@ -237,16 +235,6 @@ public void setFrameInfoSourceMethodNames(NonmovableObjectArray array) { frameInfoSourceMethodNames = NonmovableArrays.getHostedArray(array); } - @Override - public NonmovableObjectArray getFrameInfoNames() { - return NonmovableArrays.fromImageHeap(frameInfoNames); - } - - @Override - public void setFrameInfoNames(NonmovableObjectArray array) { - frameInfoNames = NonmovableArrays.getHostedArray(array); - } - @Override public void setObjectFields(NonmovableObjectArray fields) { throw VMError.shouldNotReachHere("not supported for image code"); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/MethodMetadataEncoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/MethodMetadataEncoder.java index 1c115fed93de..1d31af31d210 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/MethodMetadataEncoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/MethodMetadataEncoder.java @@ -44,6 +44,7 @@ import java.util.Set; import java.util.TreeMap; +import org.graalvm.collections.Pair; import org.graalvm.compiler.core.common.util.TypeConversion; import org.graalvm.compiler.core.common.util.UnsafeArrayTypeWriter; import org.graalvm.nativeimage.ImageSingletons; @@ -57,6 +58,7 @@ import com.oracle.svm.core.util.ByteArrayReader; import com.oracle.svm.util.ReflectionUtil; +import jdk.vm.ci.meta.JavaType; import sun.invoke.util.Wrapper; import sun.reflect.annotation.AnnotationType; import sun.reflect.annotation.TypeAnnotation; @@ -67,7 +69,7 @@ public class MethodMetadataEncoder { public static final int NO_METHOD_METADATA = -1; private CodeInfoEncoder.Encoders encoders; - private TreeMap> methodData; + private TreeMap>> methodData; private byte[] methodDataEncoding; private byte[] methodDataIndexEncoding; @@ -111,7 +113,7 @@ public void prepareMetadataForMethod(SharedMethod method, Executable reflectMeth } /* Register string values in annotations */ - registerStrings(GuardedAnnotationAccess.getDeclaredAnnotations(reflectMethod)); + registerStrings(GuardedAnnotationAccess.getDeclaredAnnotations(method)); for (Annotation[] annotations : reflectMethod.getParameterAnnotations()) { registerStrings(annotations); } @@ -126,7 +128,7 @@ public void prepareMetadataForMethod(SharedMethod method, Executable reflectMeth } SharedType declaringType = (SharedType) method.getDeclaringClass(); - methodData.computeIfAbsent(declaringType, t -> new HashSet<>()).add(reflectMethod); + methodData.computeIfAbsent(declaringType, t -> new HashSet<>()).add(Pair.create(method, reflectMethod)); } private static final Method hasRealParameterData = ReflectionUtil.lookupMethod(Executable.class, "hasRealParameterData"); @@ -135,9 +137,9 @@ private void encodeMethodMetadata() { UnsafeArrayTypeWriter dataEncodingBuffer = UnsafeArrayTypeWriter.create(ByteArrayReader.supportsUnalignedMemoryAccess()); UnsafeArrayTypeWriter indexEncodingBuffer = UnsafeArrayTypeWriter.create(ByteArrayReader.supportsUnalignedMemoryAccess()); long lastTypeID = -1; - for (Map.Entry> entry : methodData.entrySet()) { + for (Map.Entry>> entry : methodData.entrySet()) { SharedType declaringType = entry.getKey(); - Set methods = entry.getValue(); + Set> methods = entry.getValue(); long typeID = declaringType.getHub().getTypeID(); assert typeID > lastTypeID; lastTypeID++; @@ -148,62 +150,70 @@ private void encodeMethodMetadata() { long index = dataEncodingBuffer.getBytesWritten(); indexEncodingBuffer.putS4(index); dataEncodingBuffer.putUV(methods.size()); - for (Executable method : methods) { - Class declaringClass = method.getDeclaringClass(); + for (Pair method : methods) { + SharedMethod hostedMethod = method.getLeft(); + Executable reflectMethod = method.getRight(); + + Class declaringClass = getJavaClass((SharedType) hostedMethod.getDeclaringClass()); final int classIndex = encoders.sourceClasses.getIndex(declaringClass); dataEncodingBuffer.putSV(classIndex); - String name = method instanceof Constructor ? "" : ((Method) method).getName(); + String name = hostedMethod.isConstructor() ? "" : hostedMethod.getName(); final int nameIndex = encoders.sourceMethodNames.getIndex(name); dataEncodingBuffer.putSV(nameIndex); - dataEncodingBuffer.putUV(method.getModifiers()); + dataEncodingBuffer.putUV(reflectMethod.getModifiers()); - Class[] parameterTypes = method.getParameterTypes(); + /* Parameter types do not include the receiver */ + JavaType[] parameterTypes = hostedMethod.getSignature().toParameterTypes(null); dataEncodingBuffer.putUV(parameterTypes.length); - for (Class parameterType : parameterTypes) { - final int paramClassIndex = encoders.sourceClasses.getIndex(parameterType); + for (JavaType parameterType : parameterTypes) { + Class parameterClass = getJavaClass((SharedType) parameterType); + final int paramClassIndex = encoders.sourceClasses.getIndex(parameterClass); dataEncodingBuffer.putSV(paramClassIndex); } - Class returnType = method instanceof Constructor ? void.class : ((Method) method).getReturnType(); + Class returnType = void.class; + if (!hostedMethod.isConstructor()) { + returnType = getJavaClass((SharedType) hostedMethod.getSignature().getReturnType(null)); + } final int returnTypeIndex = encoders.sourceClasses.getIndex(returnType); dataEncodingBuffer.putSV(returnTypeIndex); /* Only include types that are in the image (i.e. that can actually be thrown) */ - Class[] exceptionTypes = filterTypes(method.getExceptionTypes()); + Class[] exceptionTypes = filterTypes(reflectMethod.getExceptionTypes()); dataEncodingBuffer.putUV(exceptionTypes.length); for (Class exceptionClazz : exceptionTypes) { final int exceptionClassIndex = encoders.sourceClasses.getIndex(exceptionClazz); dataEncodingBuffer.putSV(exceptionClassIndex); } - final int signatureIndex = encoders.sourceMethodNames.getIndex(getSignature(method)); + final int signatureIndex = encoders.sourceMethodNames.getIndex(getSignature(reflectMethod)); dataEncodingBuffer.putSV(signatureIndex); try { - byte[] annotations = encodeAnnotations(GuardedAnnotationAccess.getDeclaredAnnotations(method)); + byte[] annotations = encodeAnnotations(GuardedAnnotationAccess.getDeclaredAnnotations(hostedMethod)); dataEncodingBuffer.putUV(annotations.length); for (byte b : annotations) { dataEncodingBuffer.putS1(b); } - byte[] parameterAnnotations = encodeParameterAnnotations(method.getParameterAnnotations()); + byte[] parameterAnnotations = encodeParameterAnnotations(reflectMethod.getParameterAnnotations()); dataEncodingBuffer.putUV(parameterAnnotations.length); for (byte b : parameterAnnotations) { dataEncodingBuffer.putS1(b); } - byte[] typeAnnotations = encodeTypeAnnotations((TypeAnnotation[]) parseAllTypeAnnotations.invoke(null, method)); + byte[] typeAnnotations = encodeTypeAnnotations((TypeAnnotation[]) parseAllTypeAnnotations.invoke(null, reflectMethod)); dataEncodingBuffer.putUV(typeAnnotations.length); for (byte b : typeAnnotations) { dataEncodingBuffer.putS1(b); } - boolean parameterDataPresent = (boolean) hasRealParameterData.invoke(method); + boolean parameterDataPresent = (boolean) hasRealParameterData.invoke(reflectMethod); dataEncodingBuffer.putU1(parameterDataPresent ? 1 : 0); if (parameterDataPresent) { - Parameter[] parameters = method.getParameters(); + Parameter[] parameters = reflectMethod.getParameters(); dataEncodingBuffer.putUV(parameters.length); for (Parameter parameter : parameters) { final int parameterNameIndex = encoders.sourceMethodNames.getIndex(parameter.getName()); @@ -226,6 +236,10 @@ private void encodeMethodMetadata() { indexEncodingBuffer.toArray(methodDataIndexEncoding); } + private static Class getJavaClass(SharedType sharedType) { + return sharedType.getHub().getHostedJavaClass(); + } + private Class[] filterTypes(Class[] types) { List> filteredTypes = new ArrayList<>(); for (Class type : types) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java index bc6322ac101e..895a4e7efe89 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java @@ -173,7 +173,6 @@ public static boolean walkWeakReferences(CodeInfo info, ObjectReferenceVisitor v continueVisiting = continueVisiting && NonmovableArrays.walkUnmanagedObjectArray(impl.getFrameInfoObjectConstants(), visitor); continueVisiting = continueVisiting && NonmovableArrays.walkUnmanagedObjectArray(impl.getFrameInfoSourceClasses(), visitor); continueVisiting = continueVisiting && NonmovableArrays.walkUnmanagedObjectArray(impl.getFrameInfoSourceMethodNames(), visitor); - continueVisiting = continueVisiting && NonmovableArrays.walkUnmanagedObjectArray(impl.getFrameInfoNames(), visitor); continueVisiting = continueVisiting && NonmovableArrays.walkUnmanagedObjectArray(impl.getDeoptimizationObjectConstants(), visitor); return continueVisiting; } @@ -233,12 +232,12 @@ private static void releaseMemory(CodeInfo info, boolean notifyGC) { } public static CodePointer allocateCodeMemory(UnsignedWord size) { - return (CodePointer) CommittedMemoryProvider.get().allocate(size, WordFactory.unsigned(SubstrateOptions.codeAlignment()), true); + return (CodePointer) CommittedMemoryProvider.get().allocateExecutableMemory(size, WordFactory.unsigned(SubstrateOptions.codeAlignment())); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static void releaseCodeMemory(CodePointer codeStart, UnsignedWord codeSize) { - CommittedMemoryProvider.get().free(codeStart, codeSize, WordFactory.unsigned(SubstrateOptions.codeAlignment()), true); + CommittedMemoryProvider.get().freeExecutableMemory(codeStart, codeSize, WordFactory.unsigned(SubstrateOptions.codeAlignment())); } public static void makeCodeMemoryExecutableReadOnly(CodePointer codeStart, UnsignedWord codeSize) { @@ -324,7 +323,6 @@ public static void forEachObjectArray(CodeInfo info, NonmovableArrayAction actio action.apply(impl.getFrameInfoObjectConstants()); action.apply(impl.getFrameInfoSourceClasses()); action.apply(impl.getFrameInfoSourceMethodNames()); - action.apply(impl.getFrameInfoNames()); action.apply(impl.getDeoptimizationObjectConstants()); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConditionalElement.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConditionalElement.java index c1b2c92d3082..cefaef14f10c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConditionalElement.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConditionalElement.java @@ -32,8 +32,8 @@ import org.graalvm.nativeimage.impl.ConfigurationCondition; public class ConditionalElement { - private ConfigurationCondition condition; - private T element; + private final ConfigurationCondition condition; + private final T element; public ConditionalElement(ConfigurationCondition condition, T element) { this.condition = condition; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/DeoptimizationCounters.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/DeoptimizationCounters.java index de24ee4fea0c..98d3a00f1761 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/DeoptimizationCounters.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/DeoptimizationCounters.java @@ -51,7 +51,7 @@ public static class Options { * Rewriting the stack pointer does not allow passing the start time properly through the call * stack. */ - static final FastThreadLocalLong startTime = FastThreadLocalFactory.createLong(); + static final FastThreadLocalLong startTime = FastThreadLocalFactory.createLong("DeoptimizationCounters.startTime"); @Fold public static DeoptimizationCounters counters() { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java index 54787ca1a7a6..cf65e7102af0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java @@ -1124,10 +1124,6 @@ private static void printVirtualFrame(Log log, VirtualFrame virtualFrame) { JavaConstant con = virtualFrame.getConstant(i); if (con.getJavaKind() != JavaKind.Illegal) { log.newline().string(" slot ").signed(i); - String name = frameInfo.getLocalVariableName(i); - if (name != null) { - log.string(" ").string(name); - } log.string(" kind: ").string(con.getJavaKind().toString()); if (con.getJavaKind() == JavaKind.Object) { Object val = SubstrateObjectConstant.asObject(con); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/NativeImagePatcher.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/NativeImagePatcher.java index 1bbd5db4ad3c..884bd33930cb 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/NativeImagePatcher.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/NativeImagePatcher.java @@ -30,8 +30,12 @@ public interface NativeImagePatcher { /** * Patch directly in the code buffer with an offset relative to the start of this instruction. + * + * @param methodStartAddress address of method start within runtime installed code + * @param relative pc-relative offset + * @param code machine code generated for this method */ - void patchCode(int relative, byte[] code); + void patchCode(long methodStartAddress, int relative, byte[] code); /** * The position from the beginning of the method where the patch is applied. This offset is used diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/JDKIntrinsicsFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/JDKIntrinsicsFeature.java index bf6d5ae3ce13..ec05a5642d48 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/JDKIntrinsicsFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/JDKIntrinsicsFeature.java @@ -37,6 +37,7 @@ import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.util.Providers; +import org.graalvm.compiler.replacements.arraycopy.ArrayCopyNode; import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.annotate.AutomaticFeature; @@ -82,7 +83,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec */ ValueNode nonNullSrc = b.nullCheckedValue(src); ValueNode nonNullDst = b.nullCheckedValue(dst); - b.add(new SubstrateArraycopyWithExceptionNode(nonNullSrc, srcPos, nonNullDst, dstPos, length, null, b.bci())); + b.add(new ArrayCopyNode(b.bci(), nonNullSrc, srcPos, nonNullDst, dstPos, length)); return true; } }); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/SubstrateArraycopyNode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/SubstrateArraycopyNode.java deleted file mode 100644 index 89920d15f7f4..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/SubstrateArraycopyNode.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.graal.jdk; - -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.replacements.arraycopy.ArrayCopy; -import org.graalvm.compiler.replacements.nodes.BasicArrayCopyNode; - -import jdk.vm.ci.meta.JavaKind; - -/** - * Substrate specific intrinisfication for {@link System#arraycopy}. - * - * Lowering is implemented in the platform/VM specific - * {@link org.graalvm.compiler.nodes.spi.LoweringProvider LoweringProvider}. Most of them eventually - * go through {@link SubstrateArraycopySnippets}. - * - * @see SubstrateArraycopyWithExceptionNode Variant with exception edge. - */ -@NodeInfo -public final class SubstrateArraycopyNode extends BasicArrayCopyNode { - public static final NodeClass TYPE = NodeClass.create(SubstrateArraycopyNode.class); - - protected SubstrateArraycopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind, int bci) { - super(TYPE, src, srcPos, dest, destPos, length, elementKind, bci); - if (this.elementKind == null) { - this.elementKind = ArrayCopy.selectComponentKind(this); - } - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/SubstrateArraycopySnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/SubstrateArraycopySnippets.java index 374748a75ed2..7d4555124dab 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/SubstrateArraycopySnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/SubstrateArraycopySnippets.java @@ -30,13 +30,13 @@ import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.extended.ForeignCallNode; import org.graalvm.compiler.nodes.extended.ForeignCallWithExceptionNode; import org.graalvm.compiler.nodes.java.ArrayLengthNode; import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.util.Providers; import org.graalvm.compiler.replacements.Snippets; +import org.graalvm.compiler.replacements.arraycopy.ArrayCopyNode; import org.graalvm.word.LocationIdentity; import com.oracle.svm.core.JavaMemoryUtil; @@ -61,8 +61,7 @@ public static void registerForeignCalls(SubstrateForeignCallsProvider foreignCal protected SubstrateArraycopySnippets(OptionValues options, Iterable factories, Providers providers, SnippetReflectionProvider snippetReflection, Map, NodeLoweringProvider> lowerings) { super(options, factories, providers, snippetReflection); - lowerings.put(SubstrateArraycopyNode.class, new SubstrateArraycopyLowering()); - lowerings.put(SubstrateArraycopyWithExceptionNode.class, new SubstrateArraycopyWithExceptionLowering()); + lowerings.put(ArrayCopyNode.class, new SubstrateArrayCopyLowering()); } /** @@ -112,21 +111,9 @@ private static void boundsCheck(Object fromArray, int fromIndex, Object toArray, } } - static final class SubstrateArraycopyLowering implements NodeLoweringProvider { + static final class SubstrateArrayCopyLowering implements NodeLoweringProvider { @Override - public void lower(SubstrateArraycopyNode node, LoweringTool tool) { - StructuredGraph graph = node.graph(); - ForeignCallNode call = graph.add(new ForeignCallNode(ARRAYCOPY, node.getSource(), node.getSourcePosition(), node.getDestination(), - node.getDestinationPosition(), node.getLength())); - call.setStateAfter(node.stateAfter()); - call.setBci(node.getBci()); - graph.replaceFixedWithFixed(node, call); - } - } - - static final class SubstrateArraycopyWithExceptionLowering implements NodeLoweringProvider { - @Override - public void lower(SubstrateArraycopyWithExceptionNode node, LoweringTool tool) { + public void lower(ArrayCopyNode node, LoweringTool tool) { StructuredGraph graph = node.graph(); ForeignCallWithExceptionNode call = graph.add(new ForeignCallWithExceptionNode(ARRAYCOPY, node.getSource(), node.getSourcePosition(), node.getDestination(), node.getDestinationPosition(), node.getLength())); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/SubstrateArraycopyWithExceptionNode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/SubstrateArraycopyWithExceptionNode.java deleted file mode 100644 index 14d919c33af5..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/SubstrateArraycopyWithExceptionNode.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.graal.jdk; - -import static org.graalvm.compiler.nodeinfo.InputType.Memory; -import static org.graalvm.compiler.nodeinfo.InputType.State; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64; - -import org.graalvm.compiler.core.common.type.StampFactory; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.graph.NodeInputList; -import org.graalvm.compiler.nodeinfo.NodeCycles; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.AbstractBeginNode; -import org.graalvm.compiler.nodes.FixedNode; -import org.graalvm.compiler.nodes.FrameState; -import org.graalvm.compiler.nodes.NamedLocationIdentity; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.WithExceptionNode; -import org.graalvm.compiler.nodes.memory.MemoryKill; -import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.compiler.replacements.arraycopy.ArrayCopy; -import org.graalvm.word.LocationIdentity; - -import jdk.vm.ci.meta.JavaKind; - -/** - * Substrate specific intrinisfication for {@link System#arraycopy} with an exception edge. - * - * Lowering is implemented in the platform/VM specific - * {@link org.graalvm.compiler.nodes.spi.LoweringProvider LoweringProvider}. Most of them eventually - * go through {@link SubstrateArraycopySnippets}. - * - * @see SubstrateArraycopyNode Variant without exception edge. - */ -@NodeInfo(cycles = NodeCycles.CYCLES_UNKNOWN, cyclesRationale = "may be replaced with non-throwing counterpart", size = SIZE_64) -public class SubstrateArraycopyWithExceptionNode extends WithExceptionNode implements ArrayCopy { - - public static final NodeClass TYPE = NodeClass.create(SubstrateArraycopyWithExceptionNode.class); - - @Input NodeInputList args; - @OptionalInput(State) FrameState stateDuring; - @OptionalInput(State) protected FrameState stateAfter; - @OptionalInput(Memory) protected MemoryKill lastLocationAccess; - - protected JavaKind elementKind; - - protected int bci; - - public SubstrateArraycopyWithExceptionNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind, int bci) { - super(TYPE, StampFactory.forVoid()); - this.bci = bci; - this.args = new NodeInputList<>(this, new ValueNode[]{src, srcPos, dest, destPos, length}); - this.elementKind = elementKind != JavaKind.Illegal ? elementKind : null; - if (this.elementKind == null) { - this.elementKind = ArrayCopy.selectComponentKind(this); - } - } - - @Override - public NodeInputList args() { - return args; - } - - @Override - public LocationIdentity getKilledLocationIdentity() { - return getLocationIdentity(); - } - - @Override - public LocationIdentity getLocationIdentity() { - if (elementKind != null) { - return NamedLocationIdentity.getArrayLocation(elementKind); - } - return LocationIdentity.any(); - } - - @Override - public MemoryKill getLastLocationAccess() { - return lastLocationAccess; - } - - @Override - public void setLastLocationAccess(MemoryKill lla) { - updateUsagesInterface(lastLocationAccess, lla); - lastLocationAccess = lla; - } - - @Override - public FrameState stateDuring() { - return stateDuring; - } - - @Override - public void setStateDuring(FrameState stateDuring) { - updateUsages(this.stateDuring, stateDuring); - this.stateDuring = stateDuring; - } - - @Override - public FrameState stateAfter() { - return stateAfter; - } - - @Override - public void setStateAfter(FrameState stateAfter) { - updateUsages(this.stateAfter, stateAfter); - this.stateAfter = stateAfter; - } - - @Override - public int getBci() { - return bci; - } - - @Override - public JavaKind getElementKind() { - return elementKind; - } - - @Override - public FixedNode replaceWithNonThrowing() { - SubstrateArraycopyNode plainArrayCopy = this.asNode().graph() - .add(new SubstrateArraycopyNode(getSource(), getSourcePosition(), getDestination(), getDestinationPosition(), getLength(), getElementKind(), getBci())); - plainArrayCopy.setStateAfter(stateAfter); - AbstractBeginNode oldException = this.exceptionEdge; - graph().replaceSplitWithFixed(this, plainArrayCopy, this.next()); - GraphUtil.killCFG(oldException); - return plainArrayCopy; - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java index 037bec25405d..a57361ac5bf7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java @@ -36,6 +36,7 @@ import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.TypeReference; import org.graalvm.compiler.debug.DebugHandlersFactory; +import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.CompressionNode.CompressionOp; import org.graalvm.compiler.nodes.ConstantNode; @@ -69,8 +70,8 @@ import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.config.ObjectLayout; import com.oracle.svm.core.graal.nodes.FloatingWordCastNode; -import com.oracle.svm.core.graal.nodes.SubstrateCompressionNode; import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; +import com.oracle.svm.core.graal.nodes.SubstrateCompressionNode; import com.oracle.svm.core.graal.nodes.SubstrateFieldLocationIdentity; import com.oracle.svm.core.graal.nodes.SubstrateNarrowOopStamp; import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; @@ -175,7 +176,7 @@ protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, Lower return graph.unique(new LoadHubNode(tool.getStampProvider(), object)); } - assert !object.isConstant() || object.asJavaConstant().isNull(); + GraalError.guarantee(!object.isConstant() || object.asJavaConstant().isNull(), "Object should either not be a constant or the null constant %s", object); ObjectLayout objectLayout = getObjectLayout(); Stamp headerBitsStamp = StampFactory.forUnsignedInteger(8 * objectLayout.getReferenceSize()); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateForeignCallsProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateForeignCallsProvider.java index e0aba1ccdc70..ba47837024ea 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateForeignCallsProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateForeignCallsProvider.java @@ -98,15 +98,6 @@ public void registerArrayCopyForeignCallsDelegate(ArrayCopyLookup arraycopyForei this.arrayCopyLookup = arraycopyForeignCalls; } - @Override - public ForeignCallDescriptor lookupCheckcastArraycopyDescriptor(boolean uninit) { - if (arrayCopyLookup != null) { - return arrayCopyLookup.lookupCheckcastArraycopyDescriptor(uninit); - } else { - throw VMError.unsupportedFeature("Fast checkcast ArrayCopy not supported yet."); - } - } - @Override public ForeignCallDescriptor lookupArraycopyDescriptor(JavaKind kind, boolean aligned, boolean disjoint, boolean uninit, LocationIdentity killedLocation) { if (arrayCopyLookup != null) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateLoweringProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateLoweringProvider.java index bc7e984939fe..4f75702cb5ac 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateLoweringProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateLoweringProvider.java @@ -61,4 +61,8 @@ static LoweringProvider create(MetaAccessProvider metaAccess, ForeignCallsProvid } + @Override + default boolean supportsImplicitNullChecks() { + return false; + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java index 0a7f1ddde179..d2d9d7e69566 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java @@ -211,7 +211,7 @@ public StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod parameterPlugin = new ConstantBindingParameterPlugin(args, providers.getMetaAccess(), snippetReflection); } - EncodedGraph encodedGraph = new EncodedGraph(snippetEncoding, startOffset, snippetObjects, snippetNodeClasses, null, null, null, false, trackNodeSourcePosition); + EncodedGraph encodedGraph = new EncodedGraph(snippetEncoding, startOffset, snippetObjects, snippetNodeClasses, null, null, false, trackNodeSourcePosition); try (DebugContext debug = openDebugContext("SVMSnippet_", method, options)) { StructuredGraph result = new StructuredGraph.Builder(options, debug).method(method).trackNodeSourcePosition(trackNodeSourcePosition).setIsSubstitution(true).build(); PEGraphDecoder graphDecoder = new PEGraphDecoder(ConfigurationValues.getTarget().arch, result, providers, null, snippetInvocationPlugins, new InlineInvokePlugin[0], parameterPlugin, null, diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/ExceptionStateNode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/ExceptionStateNode.java deleted file mode 100644 index 1e58d8b6c5f1..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/ExceptionStateNode.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2019, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.graal.nodes; - -import org.graalvm.compiler.core.common.type.StampFactory; -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodes.spi.Canonicalizable; -import org.graalvm.compiler.nodes.spi.CanonicalizerTool; -import org.graalvm.compiler.nodeinfo.NodeCycles; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodeinfo.NodeSize; -import org.graalvm.compiler.nodes.AbstractStateSplit; -import org.graalvm.compiler.nodes.FrameState; - -@NodeInfo(cycles = NodeCycles.CYCLES_0, size = NodeSize.SIZE_0) -public final class ExceptionStateNode extends AbstractStateSplit implements Canonicalizable { - public static final NodeClass TYPE = NodeClass.create(ExceptionStateNode.class); - - public ExceptionStateNode(FrameState stateAfter) { - super(TYPE, StampFactory.forVoid(), stateAfter); - assert stateAfter != null; - } - - @Override - public Node canonical(CanonicalizerTool tool) { - if (stateAfter == null) { - /* After the FrameStateAssignmentPhase, the node is unnecessary. */ - return null; - } - return this; - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/SubstrateReflectionGetCallerClassNode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/SubstrateReflectionGetCallerClassNode.java index 839463db4442..b0cfdde5aa93 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/SubstrateReflectionGetCallerClassNode.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/SubstrateReflectionGetCallerClassNode.java @@ -53,6 +53,6 @@ protected boolean isCallerSensitive(ResolvedJavaMethod method) { @Override protected boolean ignoredBySecurityStackWalk(MetaAccessProvider metaAccess, ResolvedJavaMethod method) { - return !StackTraceUtils.shouldShowFrame(metaAccess, method, true, false, false); + return StackTraceUtils.ignoredBySecurityStackWalk(metaAccess, method); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java index bf6fd263cc54..64dbc2d36a57 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java @@ -27,12 +27,15 @@ import static com.oracle.svm.core.SubstrateOptions.MultiThreaded; import static com.oracle.svm.core.SubstrateOptions.SpawnIsolates; import static com.oracle.svm.core.SubstrateOptions.UseDedicatedVMOperationThread; +import static com.oracle.svm.core.annotate.RestrictHeapAccess.Access.NO_ALLOCATION; import static com.oracle.svm.core.graal.nodes.WriteCurrentVMThreadNode.writeCurrentVMThread; import static com.oracle.svm.core.graal.nodes.WriteHeapBaseNode.writeCurrentVMHeapBase; import static com.oracle.svm.core.util.VMError.shouldNotReachHere; import java.util.Map; +import com.oracle.svm.core.annotate.RestrictHeapAccess; +import com.oracle.svm.core.thread.VMThreads.SafepointBehavior; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; @@ -71,7 +74,6 @@ import com.oracle.svm.core.RuntimeAssertionsSupport; import com.oracle.svm.core.SubstrateDiagnostics; import com.oracle.svm.core.SubstrateUtil; -import com.oracle.svm.core.annotate.RestrictHeapAccess; import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.c.CGlobalData; import com.oracle.svm.core.c.CGlobalDataFactory; @@ -426,7 +428,6 @@ public static int detachThreadSnippet() { @SubstrateForeignCallTarget(stubCallingConvention = false) @Uninterruptible(reason = "Thread state going away.") - @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not (thread-local) allocate while detaching a thread.") private static int detachThreadMT(IsolateThread currentThread) { try { VMThreads.singleton().detachThread(currentThread); @@ -564,15 +565,18 @@ public static int reportExceptionSnippet(Throwable exception) { @Uninterruptible(reason = "Avoid StackOverflowError and safepoints until they are disabled permanently", calleeMustBe = false) @SubstrateForeignCallTarget(stubCallingConvention = false) + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate in fatal error handling.", overridesCallers = true) private static int reportException(Throwable exception) { - VMThreads.StatusSupport.setStatusIgnoreSafepoints(); + SafepointBehavior.preventSafepoints(); StackOverflowCheck.singleton().disableStackOverflowChecksForFatalError(); logException(exception); + ImageSingletons.lookup(LogHandler.class).fatalError(); return CEntryPointErrors.UNSPECIFIED; // unreachable } + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate in fatal error handling.", overridesCallers = true) private static void logException(Throwable exception) { try { Log.log().exception(exception); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/DeoptTester.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/DeoptTester.java index c76f5a555165..670c4ef1d1ba 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/DeoptTester.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/DeoptTester.java @@ -29,7 +29,6 @@ import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.options.Option; -import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.c.function.CodePointer; import org.graalvm.word.LocationIdentity; import org.graalvm.word.Pointer; @@ -52,7 +51,7 @@ import com.oracle.svm.core.thread.JavaThreads; import com.oracle.svm.core.thread.ThreadingSupportImpl; import com.oracle.svm.core.thread.VMOperation; -import com.oracle.svm.core.thread.VMThreads; +import com.oracle.svm.core.thread.VMThreads.SafepointBehavior; import com.oracle.svm.core.threadlocal.FastThreadLocalFactory; import com.oracle.svm.core.threadlocal.FastThreadLocalInt; import com.oracle.svm.core.util.VMError; @@ -71,7 +70,7 @@ public static class Options { private static final Set handledPCs = new HashSet<>(); - private static final FastThreadLocalInt inDeoptTest = FastThreadLocalFactory.createInt(); + private static final FastThreadLocalInt inDeoptTest = FastThreadLocalFactory.createInt("DeoptTester.inDeoptTest"); private static final StackFrameVisitor collectPcVisitor = new StackFrameVisitor() { @@ -112,7 +111,7 @@ public static void deoptTest() { !CEntryPointSnippets.isIsolateInitialized() || ThreadingSupportImpl.isRecurringCallbackPaused() || VMOperation.isInProgress() || - VMThreads.StatusSupport.isStatusIgnoreSafepoints(CurrentIsolate.getCurrentThread()) || + SafepointBehavior.ignoresSafepoints() || !JavaThreads.currentJavaThreadInitialized()) { return; // Thread or VM is not in a safe (or sane) state for deoptimization } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/ExceptionSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/ExceptionSnippets.java index d1fd20b42ae3..a60d039e5563 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/ExceptionSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/ExceptionSnippets.java @@ -24,9 +24,9 @@ */ package com.oracle.svm.core.graal.snippets; -import static org.graalvm.compiler.nodes.UnreachableNode.unreachable; import static com.oracle.svm.core.graal.snippets.SubstrateIntrinsics.runtimeCall; import static com.oracle.svm.core.snippets.KnownIntrinsics.readCallerStackPointer; +import static org.graalvm.compiler.nodes.UnreachableNode.unreachable; import java.util.Map; @@ -37,7 +37,6 @@ import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.FixedWithNextNode; -import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.UnwindNode; import org.graalvm.compiler.nodes.java.LoadExceptionObjectNode; @@ -51,7 +50,6 @@ import org.graalvm.word.Pointer; import com.oracle.svm.core.annotate.NeverInline; -import com.oracle.svm.core.graal.nodes.ExceptionStateNode; import com.oracle.svm.core.graal.nodes.ReadExceptionObjectNode; import com.oracle.svm.core.meta.SharedMethod; import com.oracle.svm.core.snippets.ExceptionUnwind; @@ -102,14 +100,9 @@ public static class LoadExceptionObjectLowering implements NodeLoweringProvider< @Override public void lower(LoadExceptionObjectNode node, LoweringTool tool) { - FrameState exceptionState = node.stateAfter(); - assert exceptionState != null; - StructuredGraph graph = node.graph(); FixedWithNextNode readRegNode = graph.add(new ReadExceptionObjectNode(StampFactory.objectNonNull())); graph.replaceFixedWithFixed(node, readRegNode); - - graph.addAfterFixed(readRegNode, graph.add(new ExceptionStateNode(exceptionState))); } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java index 6c94898c9c5b..658fe5962e21 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java @@ -33,15 +33,19 @@ import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.core.common.type.StampPair; +import org.graalvm.compiler.core.common.type.TypeReference; import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeInputList; +import org.graalvm.compiler.nodes.BeginNode; import org.graalvm.compiler.nodes.CallTargetNode; import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.DirectCallTargetNode; import org.graalvm.compiler.nodes.FixedGuardNode; import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.IfNode; import org.graalvm.compiler.nodes.IndirectCallTargetNode; import org.graalvm.compiler.nodes.Invoke; import org.graalvm.compiler.nodes.InvokeNode; @@ -54,11 +58,15 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.IsNullNode; +import org.graalvm.compiler.nodes.extended.BranchProbabilityNode; import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode; import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind; +import org.graalvm.compiler.nodes.extended.FixedValueAnchorNode; import org.graalvm.compiler.nodes.extended.ForeignCallNode; import org.graalvm.compiler.nodes.extended.GetClassNode; import org.graalvm.compiler.nodes.extended.LoadHubNode; +import org.graalvm.compiler.nodes.extended.OpaqueNode; +import org.graalvm.compiler.nodes.java.InstanceOfNode; import org.graalvm.compiler.nodes.java.MethodCallTargetNode; import org.graalvm.compiler.nodes.memory.OnHeapMemoryAccess.BarrierType; import org.graalvm.compiler.nodes.memory.ReadNode; @@ -73,6 +81,8 @@ import org.graalvm.word.LocationIdentity; import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.code.CodeInfoTable; import com.oracle.svm.core.graal.code.SubstrateBackend; import com.oracle.svm.core.graal.meta.RuntimeConfiguration; @@ -81,6 +91,8 @@ import com.oracle.svm.core.meta.SharedMethod; import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.snippets.ImplicitExceptions; +import com.oracle.svm.core.snippets.SnippetRuntime; +import com.oracle.svm.core.snippets.SubstrateForeignCallTarget; import com.oracle.svm.core.util.VMError; import jdk.vm.ci.code.CallingConvention; @@ -93,9 +105,14 @@ public abstract class NonSnippetLowerings { + public static final SnippetRuntime.SubstrateForeignCallDescriptor REPORT_VERIFY_TYPES_ERROR = SnippetRuntime.findForeignCall( + NonSnippetLowerings.class, "reportVerifyTypesError", false, LocationIdentity.any()); + private final RuntimeConfiguration runtimeConfig; private final Predicate mustNotAllocatePredicate; + final boolean verifyTypes = SubstrateOptions.VerifyTypes.getValue(); + @SuppressWarnings("unused") protected NonSnippetLowerings(RuntimeConfiguration runtimeConfig, Predicate mustNotAllocatePredicate, OptionValues options, Iterable factories, Providers providers, SnippetReflectionProvider snippetReflection, Map, NodeLoweringProvider> lowerings) { @@ -123,6 +140,7 @@ protected NonSnippetLowerings(RuntimeConfiguration runtimeConfig, Predicate stackBoundaryTL = FastThreadLocalFactory.createWord().setMaxOffset(FastThreadLocal.FIRST_CACHE_LINE); + public static final FastThreadLocalWord stackBoundaryTL = FastThreadLocalFactory.createWord("StackOverflowCheckImpl.stackBoundaryTL").setMaxOffset(FastThreadLocal.FIRST_CACHE_LINE); /** * Stores a counter how often the yellow zone has been made available, so that the yellow zone @@ -108,7 +108,7 @@ public final class StackOverflowCheckImpl implements StackOverflowCheck { * 0 is the default value of thread local variables, so disallowing 0 as a valid value allows us * to to detect error in the state transitions. */ - static final FastThreadLocalInt yellowZoneStateTL = FastThreadLocalFactory.createInt(); + static final FastThreadLocalInt yellowZoneStateTL = FastThreadLocalFactory.createInt("StackOverflowCheckImpl.yellowZoneStateTL"); static final int STATE_UNINITIALIZED = 0; static final int STATE_YELLOW_ENABLED = 1; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java index 10164d1d354b..34b654e0ebba 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java @@ -50,6 +50,7 @@ import org.graalvm.compiler.nodes.PiNode; import org.graalvm.compiler.nodes.SnippetAnchorNode; import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.UnreachableNode; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.extended.ForeignCallNode; import org.graalvm.compiler.nodes.extended.ForeignCallWithExceptionNode; @@ -81,7 +82,6 @@ import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider; import com.oracle.svm.core.graal.nodes.NewStoredContinuationNode; import com.oracle.svm.core.graal.nodes.SubstrateNewHybridInstanceNode; -import org.graalvm.compiler.nodes.UnreachableNode; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.StoredContinuation; import com.oracle.svm.core.hub.DynamicHub; @@ -117,7 +117,7 @@ public static void registerForeignCalls(SubstrateForeignCallsProvider foreignCal @Snippet protected Object allocateInstance(DynamicHub hub, @ConstantParameter long size, - @ConstantParameter boolean fillContents, + @ConstantParameter FillContent fillContents, @ConstantParameter boolean emitMemoryBarrier, @ConstantParameter AllocationProfilingData profilingData) { DynamicHub checkedHub = checkHub(hub); @@ -131,7 +131,7 @@ protected Object allocateStoredContinuationInstance(DynamicHub hub, @ConstantParameter AllocationProfilingData profilingData) { DynamicHub checkedHub = checkHub(hub); Object result = allocateInstanceImpl(encodeAsTLABObjectHeader(checkedHub), WordFactory.nullPointer(), WordFactory.unsigned(size), - false, true, false, profilingData); + FillContent.WITH_GARBAGE_IF_ASSERTIONS_ENABLED, true, false, profilingData); return piCastToSnippetReplaceeStamp(result); } @@ -140,7 +140,7 @@ public Object allocateArray(DynamicHub hub, int length, @ConstantParameter int arrayBaseOffset, @ConstantParameter int log2ElementSize, - @ConstantParameter boolean fillContents, + @ConstantParameter FillContent fillContents, @ConstantParameter int fillStartOffset, @ConstantParameter boolean emitMemoryBarrier, @ConstantParameter boolean maybeUnroll, @@ -154,7 +154,7 @@ public Object allocateArray(DynamicHub hub, } @Snippet - public Object allocateInstanceDynamic(@NonNullParameter DynamicHub hub, @ConstantParameter boolean fillContents, @ConstantParameter boolean emitMemoryBarrier, + public Object allocateInstanceDynamic(@NonNullParameter DynamicHub hub, @ConstantParameter FillContent fillContents, @ConstantParameter boolean emitMemoryBarrier, @ConstantParameter AllocationProfilingData profilingData) { UnsignedWord size = LayoutEncoding.getInstanceSize(hub.getLayoutEncoding()); Object result = allocateInstanceImpl(encodeAsTLABObjectHeader(hub), WordFactory.nullPointer(), size, fillContents, emitMemoryBarrier, false, profilingData); @@ -162,7 +162,7 @@ public Object allocateInstanceDynamic(@NonNullParameter DynamicHub hub, @Constan } @Snippet - public Object allocateArrayDynamic(DynamicHub elementType, int length, @ConstantParameter boolean fillContents, @ConstantParameter boolean emitMemoryBarrier, + public Object allocateArrayDynamic(DynamicHub elementType, int length, @ConstantParameter FillContent fillContents, @ConstantParameter boolean emitMemoryBarrier, @ConstantParameter boolean supportsBulkZeroing, @ConstantParameter boolean supportsOptimizedFilling, @ConstantParameter AllocationProfilingData profilingData) { DynamicHub checkedArrayHub = getCheckedArrayHub(elementType); @@ -196,15 +196,6 @@ private static DynamicHub validateNewInstanceClass(DynamicHub hub) { /** Foreign call: {@link #NEW_MULTI_ARRAY}. */ @SubstrateForeignCallTarget(stubCallingConvention = false) private static Object newMultiArrayStub(Word dynamicHub, int rank, Word dimensionsStackValue) { - /* - * All dimensions must be checked here up front, since a previous dimension of length 0 - * stops allocation of inner dimensions. - */ - for (int i = 0; i < rank; i++) { - if (dimensionsStackValue.readInt(i * 4) < 0) { - throw new NegativeArraySizeException(); - } - } // newMultiArray does not have a fast path, so there is no need to encode the hub as an // object header. DynamicHub hub = (DynamicHub) dynamicHub.toObject(); @@ -520,7 +511,7 @@ public void lower(NewInstanceNode node, LoweringTool tool) { Arguments args = new Arguments(allocateInstance, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); args.addConst("size", size); - args.addConst("fillContents", node.fillContents()); + args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("profilingData", getProfilingData(node, type)); @@ -552,7 +543,7 @@ public void lower(SubstrateNewHybridInstanceNode node, LoweringTool tool) { args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length)); args.addConst("arrayBaseOffset", arrayBaseOffset); args.addConst("log2ElementSize", log2ElementSize); - args.addConst("fillContents", fillContents); + args.addConst("fillContents", FillContent.fromBoolean(fillContents)); args.addConst("fillStartOffset", afterArrayLengthOffset()); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("maybeUnroll", length.isConstant()); @@ -585,7 +576,7 @@ public void lower(NewArrayNode node, LoweringTool tool) { args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length)); args.addConst("arrayBaseOffset", arrayBaseOffset); args.addConst("log2ElementSize", log2ElementSize); - args.addConst("fillContents", node.fillContents()); + args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); args.addConst("fillStartOffset", afterArrayLengthOffset()); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("maybeUnroll", length.isConstant()); @@ -633,7 +624,7 @@ public void lower(DynamicNewInstanceNode node, LoweringTool tool) { Arguments args = new Arguments(allocateInstanceDynamic, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", node.getInstanceType()); - args.addConst("fillContents", node.fillContents()); + args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("profilingData", getProfilingData(node, null)); @@ -652,7 +643,7 @@ public void lower(DynamicNewArrayNode node, LoweringTool tool) { Arguments args = new Arguments(allocateArrayDynamic, graph.getGuardsStage(), tool.getLoweringStage()); args.add("elementType", node.getElementType()); args.add("length", node.length()); - args.addConst("fillContents", node.fillContents()); + args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("supportsBulkZeroing", tool.getLowerer().supportsBulkZeroing()); args.addConst("supportsOptimizedFilling", tool.getLowerer().supportsOptimizedFilling(graph.getOptions())); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateIntrinsics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateIntrinsics.java index bd151312aaa8..fb5aad712efb 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateIntrinsics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateIntrinsics.java @@ -30,6 +30,7 @@ import org.graalvm.compiler.nodes.BreakpointNode; import org.graalvm.compiler.nodes.extended.ForeignCallNode; import org.graalvm.compiler.nodes.extended.LoadHubNode; +import org.graalvm.compiler.nodes.extended.LoadHubOrNullNode; import org.graalvm.word.Pointer; import com.oracle.svm.core.hub.DynamicHub; @@ -44,6 +45,9 @@ protected interface Any { @NodeIntrinsic(LoadHubNode.class) public static native DynamicHub loadHub(Object object); + @NodeIntrinsic(LoadHubOrNullNode.class) + public static native DynamicHub loadHubOrNull(Object object); + @NodeIntrinsic(value = ForeignCallNode.class) public static native void runtimeCall(@ConstantNodeParameter ForeignCallDescriptor descriptor); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/TypeSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/TypeSnippets.java index 7f6b3c5c7305..ec5bf7fd65c3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/TypeSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/TypeSnippets.java @@ -25,6 +25,7 @@ package com.oracle.svm.core.graal.snippets; import static com.oracle.svm.core.graal.snippets.SubstrateIntrinsics.loadHub; +import static com.oracle.svm.core.graal.snippets.SubstrateIntrinsics.loadHubOrNull; import java.util.Map; @@ -38,6 +39,7 @@ import org.graalvm.compiler.nodes.PiNode; import org.graalvm.compiler.nodes.SnippetAnchorNode; import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.extended.GuardingNode; import org.graalvm.compiler.nodes.java.ClassIsAssignableFromNode; import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode; import org.graalvm.compiler.nodes.java.InstanceOfNode; @@ -47,11 +49,11 @@ import org.graalvm.compiler.replacements.InstanceOfSnippetsTemplates; import org.graalvm.compiler.replacements.SnippetTemplate; import org.graalvm.compiler.replacements.Snippets; -import org.graalvm.compiler.word.ObjectAccess; import com.oracle.svm.core.annotate.DuplicatedInNativeCode; import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.graal.meta.RuntimeConfiguration; +import com.oracle.svm.core.graal.word.DynamicHubAccess; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.meta.SharedType; @@ -66,16 +68,16 @@ protected static SubstrateIntrinsics.Any typeEqualitySnippet( SubstrateIntrinsics.Any falseValue, @Snippet.ConstantParameter boolean allowsNull, DynamicHub exactType) { - - if (object == null) { - return allowsNull ? trueValue : falseValue; + if (allowsNull) { + if (object == null) { + return trueValue; + } } - Object objectNonNull = PiNode.piCastNonNull(object, SnippetAnchorNode.anchor()); - - if (loadHub(objectNonNull) == exactType) { - return trueValue; + Object hubOrNull = loadHubOrNull(object); + if (hubOrNull != exactType) { + return falseValue; } - return falseValue; + return trueValue; } @Snippet @@ -87,12 +89,15 @@ protected static SubstrateIntrinsics.Any instanceOfSnippet( short start, short range, short slot, @Snippet.ConstantParameter int typeIDSlotOffset) { if (object == null) { - return allowsNull ? trueValue : falseValue; + if (allowsNull) { + return trueValue; + } + return falseValue; } - Object objectNonNull = PiNode.piCastNonNull(object, SnippetAnchorNode.anchor()); - DynamicHub objectHub = loadHub(objectNonNull); - - return slotTypeCheck(start, range, slot, typeIDSlotOffset, objectHub, trueValue, falseValue); + GuardingNode guard = SnippetAnchorNode.anchor(); + Object nonNullObject = PiNode.piCastNonNull(object, guard); + DynamicHub nonNullHub = loadHub(nonNullObject); + return slotTypeCheck(start, range, slot, typeIDSlotOffset, nonNullHub, trueValue, falseValue); } @Snippet @@ -104,12 +109,15 @@ protected static SubstrateIntrinsics.Any instanceOfDynamicSnippet( @Snippet.ConstantParameter boolean allowsNull, @Snippet.ConstantParameter int typeIDSlotOffset) { if (object == null) { - return allowsNull ? trueValue : falseValue; + if (allowsNull) { + return trueValue; + } + return falseValue; } - Object objectNonNull = PiNode.piCastNonNull(object, SnippetAnchorNode.anchor()); - DynamicHub objectHub = loadHub(objectNonNull); - - return slotTypeCheck(type.getTypeCheckStart(), type.getTypeCheckRange(), type.getTypeCheckSlot(), typeIDSlotOffset, objectHub, trueValue, falseValue); + GuardingNode guard = SnippetAnchorNode.anchor(); + Object nonNullObject = PiNode.piCastNonNull(object, guard); + DynamicHub nonNullHub = loadHub(nonNullObject); + return slotTypeCheck(type.getTypeCheckStart(), type.getTypeCheckRange(), type.getTypeCheckSlot(), typeIDSlotOffset, nonNullHub, trueValue, falseValue); } @Snippet @@ -132,9 +140,9 @@ private static SubstrateIntrinsics.Any slotTypeCheck( int typeCheckStart = Short.toUnsignedInt(start); int typeCheckRange = Short.toUnsignedInt(range); int typeCheckSlot = Short.toUnsignedInt(slot) * 2; - - int checkedTypeID = Short.toUnsignedInt(ObjectAccess.readShort(checkedHub, typeIDSlotOffset + typeCheckSlot, NamedLocationIdentity.FINAL_LOCATION)); - + // No need to guard reading from hub as `checkedHub` is guaranteed to be non-null. + final GuardingNode guard = null; + int checkedTypeID = Short.toUnsignedInt(DynamicHubAccess.readShort(checkedHub, typeIDSlotOffset + typeCheckSlot, NamedLocationIdentity.FINAL_LOCATION, guard)); if (UnsignedMath.belowThan(checkedTypeID - typeCheckStart, typeCheckRange)) { return trueValue; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK11To14.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/word/DynamicHubAccess.java similarity index 69% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK11To14.java rename to substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/word/DynamicHubAccess.java index b4a8261954da..e926f9110bb1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK11To14.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/word/DynamicHubAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,15 +22,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk; +package com.oracle.svm.core.graal.word; -import java.util.function.BooleanSupplier; +import org.graalvm.compiler.nodes.extended.GuardingNode; +import org.graalvm.word.LocationIdentity; -import org.graalvm.compiler.serviceprovider.JavaVersionUtil; +import com.oracle.svm.core.graal.word.SubstrateOperation.SubstrateOpcode; -public class JDK11To14 implements BooleanSupplier { - @Override - public boolean getAsBoolean() { - return JavaVersionUtil.JAVA_SPEC >= 11 && JavaVersionUtil.JAVA_SPEC <= 14; - } +public final class DynamicHubAccess { + + @SubstrateOperation(opcode = SubstrateOpcode.READ_FROM_HUB) + public static native short readShort(Object object, int offset, LocationIdentity identity, GuardingNode guard); } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapPolicyOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/word/SubstrateOperation.java similarity index 72% rename from substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapPolicyOptions.java rename to substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/word/SubstrateOperation.java index 8801d8d1cf23..1227bb12af05 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapPolicyOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/word/SubstrateOperation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,16 +22,21 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.genscavenge; +package com.oracle.svm.core.graal.word; -import com.oracle.svm.core.option.HostedOptionKey; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; -/** - * Only for compatibility with legacy code, replaced by {@link HeapParameters.Options}. - */ -public final class HeapPolicyOptions { - public static final HostedOptionKey AlignedHeapChunkSize = HeapParameters.Options.AlignedHeapChunkSize; +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface SubstrateOperation { - private HeapPolicyOptions() { + enum SubstrateOpcode { + READ_FROM_HUB } + + SubstrateOpcode opcode(); + } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/word/SubstrateWordOperationPlugins.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/word/SubstrateWordOperationPlugins.java new file mode 100644 index 000000000000..248e60b1e005 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/word/SubstrateWordOperationPlugins.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.graal.word; + +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.extended.GuardingNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.memory.FixedAccessNode; +import org.graalvm.compiler.nodes.memory.OnHeapMemoryAccess.BarrierType; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.word.WordOperationPlugin; +import org.graalvm.compiler.word.WordTypes; +import org.graalvm.util.GuardedAnnotationAccess; +import org.graalvm.word.LocationIdentity; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class SubstrateWordOperationPlugins extends WordOperationPlugin { + + public SubstrateWordOperationPlugins(SnippetReflectionProvider snippetReflection, WordTypes wordTypes) { + super(snippetReflection, wordTypes); + } + + @Override + public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + if (!wordTypes.isWordOperation(method)) { + if (!method.getDeclaringClass().equals(b.getMetaAccess().lookupJavaType(DynamicHubAccess.class))) { + return false; + } + } + + SubstrateOperation operation = GuardedAnnotationAccess.getAnnotation(method, SubstrateOperation.class); + if (operation == null) { + processWordOperation(b, args, wordTypes.getWordOperation(method, b.getMethod().getDeclaringClass())); + return true; + } + processSubstrateOperation(b, method, args, operation); + return true; + } + + protected void processSubstrateOperation(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, SubstrateOperation operation) { + switch (operation.opcode()) { + case READ_FROM_HUB: + JavaKind returnKind = method.getSignature().getReturnKind(); + GraalError.guarantee(args.length == 4, "arg length=%d operation=%s", args.length, operation); + JavaKind readKind = wordTypes.asKind(method.getSignature().getReturnType(method.getDeclaringClass())); + AddressNode address = makeAddress(b, args[0], args[1]); + LocationIdentity location; + assert args[2].isConstant() : args[2]; + location = snippetReflection.asObject(LocationIdentity.class, args[2].asJavaConstant()); + assert location != null : snippetReflection.asObject(Object.class, args[2].asJavaConstant()); + FixedAccessNode read = b.add(new ReadNode(address, location, StampFactory.forKind(readKind), BarrierType.NONE)); + if (!(args[3] instanceof ConstantNode)) { + // guard can be the null constant + read.setGuard((GuardingNode) args[3]); + } + b.push(returnKind, read); + break; + default: + throw GraalError.shouldNotReachHere("Unkown operation " + operation); + } + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java index 59a2cdb4828a..477a52857046 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java @@ -69,6 +69,7 @@ protected Heap() { * heap-specific resources, e.g., the TLAB. This method is called for every thread except the * main thread (i.e., the one that maps the image heap). */ + @Uninterruptible(reason = "Thread is detaching and holds the THREAD_MUTEX.") public abstract void detachThread(IsolateThread isolateThread); public abstract void suspendAllocation(); @@ -217,4 +218,10 @@ public List> getLoadedClasses() { * value and returns true. Otherwise, the method returns false. */ public abstract boolean printLocationInfo(Log log, UnsignedWord value, boolean allowJavaHeapAccess, boolean allowUnsafeOperations); + + /** + * (Re)computes minimum/maximum/initial sizes of space based on the available + * {@linkplain PhysicalMemory physical memory} and current runtime option values. + */ + public abstract void updateSizeParameters(); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/InstanceReferenceMapDecoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/InstanceReferenceMapDecoder.java index b5741e274894..c7df8969cf54 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/InstanceReferenceMapDecoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/InstanceReferenceMapDecoder.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.heap; +import com.oracle.svm.core.thread.JavaContinuations; import org.graalvm.word.Pointer; import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; @@ -42,7 +43,7 @@ public static boolean walkOffsetsFromPointer(Pointer baseAddress, NonmovableArra assert ReferenceMapIndex.denotesValidReferenceMap(referenceMapIndex); assert referenceMapEncoding.isNonNull(); - if (referenceMapIndex == ReferenceMapIndex.STORED_CONTINUATION) { + if (JavaContinuations.useLoom() && referenceMapIndex == ReferenceMapIndex.STORED_CONTINUATION) { return StoredContinuationImpl.walkStoredContinuationFromPointer(baseAddress, visitor, holderObject); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/NoAllocationVerifier.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/NoAllocationVerifier.java index 031de7685d7c..cc558b6f1cd5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/NoAllocationVerifier.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/NoAllocationVerifier.java @@ -37,10 +37,6 @@ * Design: There shouldn't be tests for a locked heap on the allocation fast-path, so the key is * that creating one of these sets top to end in the young space, so allocation attempts fail over * to the slow-path, and there can be a test for a locked heap on the slow path. - * - * TODO: When SVM becomes multi-threaded, this should only prevent allocation on a particular - * thread. That could be done by setting the thread's TLAB to null, which should force it on to the - * slow-path to allocation a new TLAB. */ public class NoAllocationVerifier implements AutoCloseable { @@ -61,7 +57,7 @@ public static void exit(final String callSite, final String typeName) { throw VMError.shouldNotReachHere(ERROR_MSG); } - private static final FastThreadLocalObject openVerifiers = FastThreadLocalFactory.createObject(NoAllocationVerifier.class); + private static final FastThreadLocalObject openVerifiers = FastThreadLocalFactory.createObject(NoAllocationVerifier.class, "NoAllocationVerifier.openVerifiers"); /** * Create an opened instance. diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_PhantomReference.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_PhantomReference.java index 0537604c629b..e6a3b291f5d8 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_PhantomReference.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_PhantomReference.java @@ -30,12 +30,12 @@ import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.annotate.TargetElement; -import com.oracle.svm.core.jdk.JDK16OrLater; +import com.oracle.svm.core.jdk.JDK17OrLater; @TargetClass(PhantomReference.class) public final class Target_java_lang_ref_PhantomReference { @Substitute - @TargetElement(onlyWith = JDK16OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) boolean refersTo0(Object obj) { return ReferenceInternals.refersTo(SubstrateUtil.cast(this, PhantomReference.class), obj); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_Reference.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_Reference.java index 75ad1fed197e..848b5db4978e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_Reference.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_Reference.java @@ -31,12 +31,12 @@ import java.lang.reflect.Field; import java.util.function.BooleanSupplier; -import com.oracle.svm.core.SubstrateUtil; import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.annotate.ExcludeFromReferenceMap; @@ -50,7 +50,8 @@ import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.annotate.UnknownClass; import com.oracle.svm.core.jdk.JDK11OrLater; -import com.oracle.svm.core.jdk.JDK16OrLater; +import com.oracle.svm.core.jdk.JDK17OrLater; +import com.oracle.svm.core.jdk.JDK17_0_2OrLater; import com.oracle.svm.core.jdk.JDK8OrEarlier; import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.ReflectionUtil; @@ -133,17 +134,21 @@ public void clear() { } @Substitute - @TargetElement(onlyWith = JDK16OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) private void clear0() { clear(); } @KeepOriginal - @TargetElement(onlyWith = JDK16OrLater.class) + @TargetElement(onlyWith = JDK17_0_2OrLater.class) + native boolean refersToImpl(T obj); + + @KeepOriginal + @TargetElement(onlyWith = JDK17OrLater.class) public native boolean refersTo(T obj); @Substitute - @TargetElement(onlyWith = JDK16OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) boolean refersTo0(Object obj) { return ReferenceInternals.refersTo(SubstrateUtil.cast(this, Reference.class), obj); } @@ -199,11 +204,11 @@ static void reachabilityFence(Object ref) { } @KeepOriginal - @TargetElement(onlyWith = JDK16OrLater.class) // + @TargetElement(onlyWith = JDK17OrLater.class) // native T getFromInactiveFinalReference(); @Substitute // - @TargetElement(onlyWith = JDK16OrLater.class) // + @TargetElement(onlyWith = JDK17OrLater.class) // void clearInactiveFinalReference() { // assert this instanceof FinalReference; assert next != null; // I.e. FinalReference is inactive diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_jdk_internal_ref_Cleaner.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_jdk_internal_ref_Cleaner.java index c610ee7be797..fab9b8081c7e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_jdk_internal_ref_Cleaner.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_jdk_internal_ref_Cleaner.java @@ -35,8 +35,8 @@ import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.annotate.TargetElement; +import com.oracle.svm.core.jdk.JDK11OrEarlier; import com.oracle.svm.core.jdk.JDK11OrLater; -import com.oracle.svm.core.jdk.JDK15OrEarlier; @Platforms(Platform.HOSTED_ONLY.class) class Package_jdk_internal_ref implements Function { @@ -99,11 +99,11 @@ final class Target_jdk_internal_ref_CleanerImpl { Target_jdk_internal_ref_PhantomCleanable phantomCleanableList; @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.NewInstance, declClassName = "jdk.internal.ref.CleanerImpl$WeakCleanableRef")// - @TargetElement(onlyWith = JDK15OrEarlier.class) // + @TargetElement(onlyWith = JDK11OrEarlier.class) // Target_jdk_internal_ref_WeakCleanable weakCleanableList; @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.NewInstance, declClassName = "jdk.internal.ref.CleanerImpl$SoftCleanableRef")// - @TargetElement(onlyWith = JDK15OrEarlier.class) // + @TargetElement(onlyWith = JDK11OrEarlier.class) // Target_jdk_internal_ref_SoftCleanable softCleanableList; @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.NewInstance, declClassName = "java.lang.ref.ReferenceQueue")// @@ -114,12 +114,12 @@ final class Target_jdk_internal_ref_CleanerImpl { final class Target_jdk_internal_ref_PhantomCleanable { } -// Removed by JDK-8251861 in JDK 16 -@TargetClass(className = "jdk.internal.ref.WeakCleanable", onlyWith = {JDK11OrLater.class, JDK15OrEarlier.class}) +// Removed by JDK-8251861 +@TargetClass(className = "jdk.internal.ref.WeakCleanable", onlyWith = {JDK11OrLater.class, JDK11OrEarlier.class}) final class Target_jdk_internal_ref_WeakCleanable { } -// Removed by JDK-8251861 in JDK 16 -@TargetClass(className = "jdk.internal.ref.SoftCleanable", onlyWith = {JDK11OrLater.class, JDK15OrEarlier.class}) +// Removed by JDK-8251861 +@TargetClass(className = "jdk.internal.ref.SoftCleanable", onlyWith = {JDK11OrLater.class, JDK11OrEarlier.class}) final class Target_jdk_internal_ref_SoftCleanable { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java index d83b17f47a47..d7d7972786d3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java @@ -79,8 +79,7 @@ import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode; import com.oracle.svm.core.code.CodeInfoDecoder; import com.oracle.svm.core.jdk.JDK11OrLater; -import com.oracle.svm.core.jdk.JDK15OrLater; -import com.oracle.svm.core.jdk.JDK16OrLater; +import com.oracle.svm.core.jdk.JDK17OrLater; import com.oracle.svm.core.jdk.JDK8OrEarlier; import com.oracle.svm.core.jdk.Package_jdk_internal_reflect; import com.oracle.svm.core.jdk.Resources; @@ -176,12 +175,12 @@ public final class DynamicHub implements JavaKind.FormatWithToString, AnnotatedE private static final int IS_INSTANTIATED_FLAG_BIT = 0; /** - * Is this a Hidden Class (Since JDK 15). + * Is this a Hidden Class. */ private static final int IS_HIDDED_FLAG_BIT = 1; /** - * Is this a Record Class (Since JDK 15). + * Is this a Record Class. */ private static final int IS_RECORD_FLAG_BIT = 2; @@ -807,13 +806,13 @@ private boolean isAnonymousClass() { } @Substitute - @TargetElement(onlyWith = JDK15OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) public boolean isHidden() { return isFlagSet(IS_HIDDED_FLAG_BIT); } @Substitute - @TargetElement(onlyWith = JDK15OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) public boolean isRecord() { return isFlagSet(IS_RECORD_FLAG_BIT); } @@ -1283,11 +1282,11 @@ private Method[] privateGetPublicMethods() { } @KeepOriginal - @TargetElement(onlyWith = JDK16OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) private native Target_java_lang_reflect_RecordComponent[] getRecordComponents(); @Substitute - @TargetElement(onlyWith = JDK16OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) private Target_java_lang_reflect_RecordComponent[] getRecordComponents0() { Object[] result = rd.recordComponents; if (result == null) { @@ -1567,14 +1566,14 @@ private Class[] getNestMembers() { } @Substitute - @TargetElement(onlyWith = JDK15OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) @Override public DynamicHub componentType() { return componentType; } @Substitute - @TargetElement(onlyWith = JDK15OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) @Override public DynamicHub arrayType() { return arrayHub; @@ -1587,25 +1586,29 @@ public DynamicHub arrayType() { */ @KeepOriginal - @TargetElement(onlyWith = JDK15OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) private Class elementType() { throw VMError.unsupportedFeature("Method is not available in JDK 8 or JDK 11"); } @KeepOriginal - @TargetElement(onlyWith = JDK15OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) @Override public String descriptorString() { throw VMError.unsupportedFeature("Method is not available in JDK 8 or JDK 11"); } @KeepOriginal - @TargetElement(onlyWith = JDK15OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) @Override public Optional describeConstable() { throw VMError.unsupportedFeature("Method is not available in JDK 8 or JDK 11"); } + @KeepOriginal + @TargetElement(onlyWith = JDK17OrLater.class) + private static native String typeVarBounds(TypeVariable typeVar); + /* * We are defensive and also handle private native methods by marking them as deleted. If they * are reachable, the user is certainly doing something wrong. But we do not want to fail with a @@ -1623,8 +1626,10 @@ public Optional describeConstable() { @Delete private native Class[] getInterfaces0(); - @Delete - native void setSigners(Object[] signers); + @Substitute + private void setSigners(@SuppressWarnings("unused") Object[] signers) { + throw VMError.unsupportedFeature("Class metadata cannot be changed at run time"); + } @Delete private native java.security.ProtectionDomain getProtectionDomain0(); @@ -1687,21 +1692,21 @@ public Optional describeConstable() { */ @Substitute -@TargetClass(className = "java.lang.constant.Constable", onlyWith = JDK15OrLater.class) +@TargetClass(className = "java.lang.constant.Constable", onlyWith = JDK17OrLater.class) interface Target_java_lang_constant_Constable { @KeepOriginal Optional describeConstable(); } @Substitute -@TargetClass(className = "java.lang.invoke.TypeDescriptor", onlyWith = JDK15OrLater.class) +@TargetClass(className = "java.lang.invoke.TypeDescriptor", onlyWith = JDK17OrLater.class) interface Target_java_lang_invoke_TypeDescriptor { @KeepOriginal String descriptorString(); } @Substitute -@TargetClass(className = "java.lang.invoke.TypeDescriptor", innerClass = "OfField", onlyWith = JDK15OrLater.class) +@TargetClass(className = "java.lang.invoke.TypeDescriptor", innerClass = "OfField", onlyWith = JDK17OrLater.class) interface Target_java_lang_invoke_TypeDescriptor_OfField> extends Target_java_lang_invoke_TypeDescriptor { @KeepOriginal boolean isArray(); @@ -1737,6 +1742,6 @@ public static Target_jdk_internal_reflect_ReflectionFactory getReflectionFactory } } -@TargetClass(className = "java.lang.reflect.RecordComponent", onlyWith = JDK16OrLater.class) +@TargetClass(className = "java.lang.reflect.RecordComponent", onlyWith = JDK17OrLater.class) final class Target_java_lang_reflect_RecordComponent { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/LayoutEncoding.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/LayoutEncoding.java index 9388cd6dcf01..bae520de89a6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/LayoutEncoding.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/LayoutEncoding.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.hub; +import com.oracle.svm.core.annotate.AlwaysInline; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.core.common.calc.UnsignedMath; import org.graalvm.compiler.nodes.java.ArrayLengthNode; @@ -210,6 +211,12 @@ public static UnsignedWord getArraySize(int encoding, int length) { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static UnsignedWord getSizeFromObject(Object obj) { + return getSizeFromObjectInline(obj); + } + + @AlwaysInline("GC performance") + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static UnsignedWord getSizeFromObjectInline(Object obj) { int encoding = KnownIntrinsics.readHub(obj).getLayoutEncoding(); if (isArray(encoding)) { return getArraySize(encoding, ArrayLengthNode.arrayLength(obj)); @@ -222,11 +229,16 @@ public static UnsignedWord getSizeFromObject(Object obj) { /** Returns the end of the Object when the call started, e.g., for logging. */ public static Pointer getObjectEnd(Object obj) { + return getObjectEndInline(obj); + } + + @AlwaysInline("GC performance") + public static Pointer getObjectEndInline(Object obj) { // TODO: This assumes that the object starts at obj. // - In other universes obj could point to the hub in the middle of, // for example, a butterfly object. final Pointer objStart = Word.objectToUntrackedPointer(obj); - final UnsignedWord objSize = getSizeFromObject(obj); + final UnsignedWord objSize = getSizeFromObjectInline(obj); return objStart.add(objSize); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/identityhashcode/IdentityHashCodeSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/identityhashcode/IdentityHashCodeSupport.java index 8796e8e3ddf2..f58dcb60df8b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/identityhashcode/IdentityHashCodeSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/identityhashcode/IdentityHashCodeSupport.java @@ -46,7 +46,7 @@ public final class IdentityHashCodeSupport { public static final LocationIdentity IDENTITY_HASHCODE_LOCATION = NamedLocationIdentity.mutable("identityHashCode"); - private static final FastThreadLocalObject hashCodeGeneratorTL = FastThreadLocalFactory.createObject(SplittableRandom.class); + private static final FastThreadLocalObject hashCodeGeneratorTL = FastThreadLocalFactory.createObject(SplittableRandom.class, "IdentityHashCodeSupport.hashCodeGeneratorTL"); /** * Initialization can require synchronization which is not allowed during safepoints, so this diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK16OrEarlier.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK16OrEarlier.java deleted file mode 100644 index 8e0738e42b8f..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK16OrEarlier.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.jdk; - -import java.util.function.BooleanSupplier; - -import org.graalvm.compiler.serviceprovider.JavaVersionUtil; - -public class JDK16OrEarlier implements BooleanSupplier { - @Override - public boolean getAsBoolean() { - return JavaVersionUtil.JAVA_SPEC <= 16; - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK11_0_11OrLater.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK17_0_2OrLater.java similarity index 87% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK11_0_11OrLater.java rename to substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK17_0_2OrLater.java index cf6f5c52a22c..05a7fe4f401b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK11_0_11OrLater.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK17_0_2OrLater.java @@ -26,13 +26,15 @@ import java.util.function.BooleanSupplier; -import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.compiler.serviceprovider.GraalServices; +import org.graalvm.compiler.serviceprovider.JavaVersionUtil; + +public class JDK17_0_2OrLater implements BooleanSupplier { -public class JDK11_0_11OrLater implements BooleanSupplier { @Override public boolean getAsBoolean() { - return JavaVersionUtil.JAVA_SPEC > 11 || - (JavaVersionUtil.JAVA_SPEC == 11 && GraalServices.getJavaUpdateVersion() > 10); + return JavaVersionUtil.JAVA_SPEC > 17 || + (JavaVersionUtil.JAVA_SPEC == 17 && GraalServices.getJavaUpdateVersion() > 1); } + } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JRTSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JRTSupport.java index 0be2c83ea3bb..2cf9b5e1f024 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JRTSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JRTSupport.java @@ -136,8 +136,10 @@ final class Target_jdk_internal_jimage_ImageReaderFactory_JRTEnabled { */ @TargetClass(className = "jdk.internal.module.SystemModuleFinders", innerClass = "SystemImage", onlyWith = {JDK11OrLater.class, JRTDisabled.class}) final class Target_jdk_internal_module_SystemModuleFinders_SystemImage_JRTDisabled { - @Delete - static native Object reader(); + @Substitute + static Object reader() { + throw VMError.unsupportedFeature("JRT file system is disabled"); + } } @TargetClass(className = "sun.net.www.protocol.jrt.Handler", onlyWith = {JDK11OrLater.class, JRTDisabled.class}) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java index cc63053484bf..44394c64a92c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java @@ -647,7 +647,7 @@ static void disable() { final class Target_java_lang_NullPointerException { @Substitute - @TargetElement(onlyWith = JDK14OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) @SuppressWarnings("static-method") private String getExtendedNPEMessage() { return null; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Package_jdk_internal_loader_helper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Package_jdk_internal_loader_helper.java index dd2ba22bd3fb..bbf64c8771e3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Package_jdk_internal_loader_helper.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Package_jdk_internal_loader_helper.java @@ -37,7 +37,7 @@ public class Package_jdk_internal_loader_helper implements Function() { @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RecomputedFields.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RecomputedFields.java index 84c5399e46ca..17bacdf4750a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RecomputedFields.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RecomputedFields.java @@ -418,9 +418,9 @@ static Executor get() { } } -@TargetClass(value = java.util.concurrent.ForkJoinTask.class, onlyWith = JDK16OrEarlier.class) +@TargetClass(value = java.util.concurrent.ForkJoinTask.class, onlyWith = JDK11OrEarlier.class) @SuppressWarnings("static-method") -final class Target_java_util_concurrent_ForkJoinTask_JDK16OrEarlier { +final class Target_java_util_concurrent_ForkJoinTask_JDK11OrEarlier { @Alias @RecomputeFieldValue(kind = Kind.FromAlias) // private static Target_java_util_concurrent_ForkJoinTask_ExceptionNode[] exceptionTable; @Alias @RecomputeFieldValue(kind = Kind.FromAlias) // @@ -439,7 +439,7 @@ final class Target_java_util_concurrent_ForkJoinTask_JDK16OrEarlier { } } -@TargetClass(value = java.util.concurrent.ForkJoinTask.class, innerClass = "ExceptionNode", onlyWith = JDK16OrEarlier.class) +@TargetClass(value = java.util.concurrent.ForkJoinTask.class, innerClass = "ExceptionNode", onlyWith = JDK11OrEarlier.class) final class Target_java_util_concurrent_ForkJoinTask_ExceptionNode { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RecordSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RecordSupport.java index ff0c3dfb39e4..7e984ef46823 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RecordSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RecordSupport.java @@ -78,10 +78,10 @@ public static RecordSupport singleton() { } /** - * Placeholder implementation for old JDK version that do not have Record classes. Since + * Placeholder implementation for JDK versions that do not have Record classes. Since * {@link #isRecord} always returns false, the other methods must never be invoked. */ -final class RecordSupportBeforeJDK16 extends RecordSupport { +final class RecordSupportJDK11OrEarlier extends RecordSupport { @Override public boolean isRecord(Class clazz) { return false; @@ -104,14 +104,14 @@ public Constructor getCanonicalRecordConstructor(Class clazz) { } @AutomaticFeature -final class RecordFeatureBeforeJDK16 implements Feature { +final class RecordFeatureBeforeJDK17 implements Feature { @Override public boolean isInConfiguration(IsInConfigurationAccess access) { - return JavaVersionUtil.JAVA_SPEC < 16; + return JavaVersionUtil.JAVA_SPEC <= 11; } @Override public void afterRegistration(AfterRegistrationAccess access) { - ImageSingletons.add(RecordSupport.class, new RecordSupportBeforeJDK16()); + ImageSingletons.add(RecordSupport.class, new RecordSupportJDK11OrEarlier()); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java index 82c9f433d685..7a365e2666c0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java @@ -31,13 +31,12 @@ import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.List; -import com.oracle.svm.core.jdk.resources.ResourceStorageEntry; -import com.oracle.svm.core.jdk.resources.ResourceURLConnection; import org.graalvm.collections.EconomicMap; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; @@ -45,6 +44,9 @@ import org.graalvm.nativeimage.hosted.Feature; import com.oracle.svm.core.annotate.AutomaticFeature; +import com.oracle.svm.core.jdk.resources.NativeImageResourcePath; +import com.oracle.svm.core.jdk.resources.ResourceStorageEntry; +import com.oracle.svm.core.jdk.resources.ResourceURLConnection; import com.oracle.svm.core.util.ImageHeapMap; import com.oracle.svm.core.util.VMError; @@ -57,6 +59,8 @@ */ public final class Resources { + public static final char RESOURCES_INTERNAL_PATH_SEPARATOR = '/'; + public static Resources singleton() { return ImageSingletons.lookup(Resources.class); } @@ -121,6 +125,15 @@ public static void registerDirectoryResource(String resourceDirName, String cont addEntry(resourceDirName, true, content.getBytes()); } + /** + * Avoid pulling native file system by using {@link NativeImageResourcePath} implementation to + * convert resourceName to canonical variant. + */ + public static String toCanonicalForm(String resourceName) { + NativeImageResourcePath path = new NativeImageResourcePath(null, resourceName.getBytes(StandardCharsets.UTF_8), true); + return new String(NativeImageResourcePath.getResolved(path)); + } + public static ResourceStorageEntry get(String name) { return singleton().resources.get(name); } @@ -144,7 +157,8 @@ public static URL createURL(String resourceName) { if (resourceName == null) { return null; } - Enumeration urls = createURLs(resourceName); + + Enumeration urls = createURLs(toCanonicalForm(resourceName)); return urls.hasMoreElements() ? urls.nextElement() : null; } @@ -153,7 +167,8 @@ public static InputStream createInputStream(String resourceName) { if (resourceName == null) { return null; } - ResourceStorageEntry entry = Resources.get(resourceName); + + ResourceStorageEntry entry = Resources.get(toCanonicalForm(resourceName)); if (entry == null) { return null; } @@ -165,14 +180,16 @@ public static Enumeration createURLs(String resourceName) { if (resourceName == null) { return null; } - ResourceStorageEntry entry = Resources.get(resourceName); + + String canonicalResourceName = toCanonicalForm(resourceName); + ResourceStorageEntry entry = Resources.get(canonicalResourceName); if (entry == null) { return Collections.emptyEnumeration(); } int numberOfResources = entry.getData().size(); List resourcesURLs = new ArrayList<>(numberOfResources); for (int index = 0; index < numberOfResources; index++) { - resourcesURLs.add(createURL(resourceName, index)); + resourcesURLs.add(createURL(canonicalResourceName, index)); } return Collections.enumeration(resourcesURLs); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java index 428371a714b9..2eb7250dd07c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java @@ -308,7 +308,7 @@ final class Target_javax_crypto_JceSecurity { * * This is only used in {@link KeyAgreement}, it's safe to remove. */ - @Alias @TargetElement(onlyWith = JDK15OrEarlier.class) // + @Alias @TargetElement(onlyWith = JDK11OrEarlier.class) // @InjectAccessors(JceSecurityAccessor.class) // static SecureRandom RANDOM; @@ -376,7 +376,7 @@ public Object transform(MetaAccessProvider metaAccess, ResolvedJavaField origina } } -@TargetClass(className = "javax.crypto.JceSecurity", innerClass = "IdentityWrapper", onlyWith = JDK16OrLater.class) +@TargetClass(className = "javax.crypto.JceSecurity", innerClass = "IdentityWrapper", onlyWith = JDK17OrLater.class) @SuppressWarnings({"unused"}) final class Target_javax_crypto_JceSecurity_IdentityWrapper { @Alias // @@ -419,10 +419,10 @@ private static synchronized SecureRandom initializeOnce() { final class JceSecurityUtil { static Object providerKey(Provider p) { - if (JavaVersionUtil.JAVA_SPEC < 16) { + if (JavaVersionUtil.JAVA_SPEC <= 11) { return p; } - /* Starting with JDK 16 the verification results map key is an identity wrapper object. */ + /* Starting with JDK 17 the verification results map key is an identity wrapper object. */ return new Target_javax_crypto_JceSecurity_IdentityWrapper(p); } @@ -532,30 +532,33 @@ private static PermissionCollection allPermissions() { } @Override + @SuppressWarnings("deprecation") // deprecated starting JDK 17 public PermissionCollection getPermissions(CodeSource codesource) { return allPermissions(); } @Override + @SuppressWarnings("deprecation") // deprecated starting JDK 17 public PermissionCollection getPermissions(ProtectionDomain domain) { return allPermissions(); } @Override + @SuppressWarnings("deprecation") // deprecated starting JDK 17 public boolean implies(ProtectionDomain domain, Permission permission) { return true; } } /** - * This class is instantiated indirectly from the {@link Policy#getInstance} methods via the + * This class is instantiated indirectly from the {@code Policy#getInstance} methods via the * {@link java.security.Security#getProviders security provider} abstractions. We could just - * substitute the {@link Policy#getInstance} methods to return - * {@link AllPermissionsPolicy#SINGLETON}, this version is more fool-proof in case someone manually - * registers security providers for reflective instantiation. + * substitute the Policy.getInstance methods to return {@link AllPermissionsPolicy#SINGLETON}, this + * version is more fool-proof in case someone manually registers security providers for reflective + * instantiation. */ @TargetClass(className = "sun.security.provider.PolicySpiFile") -@SuppressWarnings({"unused", "static-method"}) +@SuppressWarnings({"unused", "static-method", "deprecation"}) final class Target_sun_security_provider_PolicySpiFile { @Substitute @@ -563,16 +566,19 @@ private Target_sun_security_provider_PolicySpiFile(Policy.Parameters params) { } @Substitute + @SuppressWarnings("deprecation") // deprecated starting JDK 17 private PermissionCollection engineGetPermissions(CodeSource codesource) { return AllPermissionsPolicy.SINGLETON.getPermissions(codesource); } @Substitute + @SuppressWarnings("deprecation") // deprecated starting JDK 17 private PermissionCollection engineGetPermissions(ProtectionDomain d) { return AllPermissionsPolicy.SINGLETON.getPermissions(d); } @Substitute + @SuppressWarnings("deprecation") // deprecated starting JDK 17 private boolean engineImplies(ProtectionDomain d, Permission p) { return AllPermissionsPolicy.SINGLETON.implies(d, p); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java index fd0712617a24..e7275cfede50 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java @@ -171,6 +171,10 @@ public static boolean shouldShowFrame(MetaAccessProvider metaAccess, ResolvedJav return true; } + public static boolean ignoredBySecurityStackWalk(MetaAccessProvider metaAccess, ResolvedJavaMethod method) { + return !shouldShowFrame(metaAccess, method, true, false, false); + } + public static ClassLoader latestUserDefinedClassLoader(Pointer startSP) { GetLatestUserDefinedClassLoaderVisitor visitor = new GetLatestUserDefinedClassLoaderVisitor(); JavaStackWalker.walkCurrentThread(startSP, visitor); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SunMiscSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SunMiscSubstitutions.java index d2439f7f6ab1..fdfcc3c478ba 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SunMiscSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SunMiscSubstitutions.java @@ -145,10 +145,6 @@ private void setMemory0(Object destBase, long destOffset, long bytes, byte bvalu @Substitute private int addressSize() { - /* - * JDK 14 now injects Unsafe contants via the Hotspot VM, so we just determine the size of - * pointers ourself. - */ return ConfigurationValues.getTarget().wordSize; } @@ -208,7 +204,7 @@ private Class defineClass(String name, byte[] b, int off, int len, ClassLoade // JDK-8243287 @Substitute - @TargetElement(onlyWith = JDK16OrEarlier.class) + @TargetElement(onlyWith = JDK11OrEarlier.class) private Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches) { throw VMError.unsupportedFeature("Defining anonymous classes at runtime is not supported."); } @@ -290,7 +286,7 @@ private Class defineClass0(String name, byte[] b, int off, int len, ClassLoad // JDK-8243287 @Delete - @TargetElement(onlyWith = JDK11To16.class) + @TargetElement(onlyWith = {JDK11OrLater.class, JDK11OrEarlier.class}) private native Class defineAnonymousClass0(Class hostClass, byte[] data, Object[] cpPatches); @Delete diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SunNioSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SunNioSubstitutions.java index 306cb60b80e2..4106a14d6f90 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SunNioSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SunNioSubstitutions.java @@ -31,7 +31,7 @@ import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.util.VMError; -@TargetClass(className = "java.nio.channels.spi.SelectorProvider", onlyWith = JDK14OrEarlier.class) +@TargetClass(className = "java.nio.channels.spi.SelectorProvider", onlyWith = JDK11OrEarlier.class) final class Target_java_nio_channels_spi_SelectorProvider { @Alias// @@ -57,7 +57,7 @@ static SelectorProvider provider() { } } -@TargetClass(className = "java.nio.channels.spi.SelectorProvider", innerClass = "Holder", onlyWith = JDK15OrLater.class) +@TargetClass(className = "java.nio.channels.spi.SelectorProvider", innerClass = "Holder", onlyWith = JDK17OrLater.class) final class Target_java_nio_channels_spi_SelectorProvider_Holder { @Alias// diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java index a51b8b25800e..74ff72b34210 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java @@ -30,6 +30,8 @@ import java.security.ProtectionDomain; import java.util.Enumeration; import java.util.HashMap; +import java.util.Map; +import java.util.Set; import java.util.Vector; import java.util.concurrent.ConcurrentHashMap; @@ -124,8 +126,8 @@ public static InputStream getSystemResourceAsStream(String name) { @Substitute @SuppressWarnings("unused") - @TargetElement(onlyWith = JDK14OrEarlier.class) // - /* Substitution for JDK 15 and later is in Target_java_lang_ClassLoader_JDK15OrLater. */ + @TargetElement(onlyWith = JDK11OrEarlier.class) // + /* Substitution for JDK 17 and later is in Target_java_lang_ClassLoader_JDK17OrLater. */ static void loadLibrary(Class fromClass, String name, boolean isAbsolute) { if (isAbsolute) { NativeLibrarySupport.singleton().loadLibraryAbsolute(new File(name)); @@ -169,7 +171,7 @@ Class loadClass(String name, boolean resolve) throws ClassNotFoundException { } @Delete - @TargetElement(onlyWith = JDK16OrEarlier.class) + @TargetElement(onlyWith = JDK11OrEarlier.class) native Class findBootstrapClassOrNull(String name); // JDK-8265605 @@ -242,6 +244,9 @@ private void clearAssertionStatus() { throw VMError.unsupportedFeature("The assertion status of classes is fixed at image build time."); } + @Delete + private native void initializeJavaAssertionMaps(); + /* * We are defensive and also handle private native methods by marking them as deleted. If they * are reachable, the user is certainly doing something wrong. But we do not want to fail with a @@ -251,6 +256,9 @@ private void clearAssertionStatus() { @Delete private static native void registerNatives(); + @Delete + private static native long findNative(ClassLoader loader, String entryName); + @Substitute @SuppressWarnings({"unused", "static-method"}) Class defineClass(byte[] b, int off, int len) throws ClassFormatError { @@ -319,7 +327,7 @@ protected void resolveClass(@SuppressWarnings("unused") Class c) { private static native Class defineClass2(ClassLoader loader, String name, java.nio.ByteBuffer b, int off, int len, ProtectionDomain pd, String source); @Delete - @TargetElement(onlyWith = JDK16OrEarlier.class) + @TargetElement(onlyWith = JDK11OrEarlier.class) private native Class findBootstrapClass(String name); // JDK-8265605 @@ -328,14 +336,49 @@ protected void resolveClass(@SuppressWarnings("unused") Class c) { private static native Class findBootstrapClassJDK17OrLater(String name); @Delete - @TargetElement(onlyWith = JDK14OrEarlier.class) + @TargetElement(onlyWith = JDK11OrEarlier.class) private static native String findBuiltinLib(String name); @Delete private static native Target_java_lang_AssertionStatusDirectives retrieveDirectives(); + + /* + * Ensure that fields and methods that hold state of the image generator are not reachable when + * all fields or methods of the class are registered for reflection. + */ + + @Delete // + @TargetElement(onlyWith = {JDK11OrLater.class, JDK11OrEarlier.class}) // + private static Set loadedLibraryNames; + @Delete // + @TargetElement(onlyWith = {JDK11OrLater.class, JDK11OrEarlier.class}) // + private static Map systemNativeLibraries; + @Delete // + @TargetElement(onlyWith = {JDK11OrLater.class, JDK11OrEarlier.class}) // + private Map nativeLibraries; + // Checkstyle: stop + @Delete // + @TargetElement(onlyWith = JDK11OrEarlier.class) // + private static String[] usr_paths; + @Delete // + @TargetElement(onlyWith = JDK11OrEarlier.class) // + private static String[] sys_paths; + // Checkstyle: resume + + @Delete + @TargetElement(onlyWith = {JDK11OrLater.class, JDK11OrEarlier.class}) + private native Map nativeLibraries(); + + @Delete + @TargetElement(onlyWith = {JDK11OrLater.class, JDK11OrEarlier.class}) + private static native Map systemNativeLibraries(); + + @Delete + @TargetElement(onlyWith = JDK11OrEarlier.class) + private static native boolean loadLibrary0(Class fromClass, File file); } -@TargetClass(value = ClassLoader.class, innerClass = "NativeLibrary", onlyWith = JDK14OrEarlier.class) +@TargetClass(value = ClassLoader.class, innerClass = "NativeLibrary", onlyWith = JDK11OrEarlier.class) final class Target_java_lang_ClassLoader_NativeLibrary { /* diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_javax_net_ssl_SSLContext.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_javax_net_ssl_SSLContext.java deleted file mode 100644 index e13e9ab406c6..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_javax_net_ssl_SSLContext.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.jdk; - -import javax.net.ssl.SSLContext; - -import com.oracle.svm.core.annotate.Alias; -import com.oracle.svm.core.annotate.RecomputeFieldValue; -import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind; -import com.oracle.svm.core.annotate.TargetClass; - -/** - * The class SSLContext has a VarHandle field on JDK 15 and later, so we cannot initialize the class - * at run time. We therefore reset just the single static field that is lazily initialized. - */ -@TargetClass(javax.net.ssl.SSLContext.class) -final class Target_javax_net_ssl_SSLContext { - - @Alias @RecomputeFieldValue(kind = Kind.Reset) // - private static volatile SSLContext defaultContext; -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_util_StaticProperty.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_util_StaticProperty.java index ce5669f7fd7f..29d0e0d88861 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_util_StaticProperty.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_util_StaticProperty.java @@ -63,26 +63,26 @@ private static String userName() { } @Substitute - @TargetElement(onlyWith = JDK16OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) private static String javaIoTmpDir() { return ImageSingletons.lookup(SystemPropertiesSupport.class).tmpDir(); } @Substitute - @TargetElement(onlyWith = JDK15OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) private static String javaLibraryPath() { return ImageSingletons.lookup(SystemPropertiesSupport.class).javaLibraryPath(); } @Substitute - @TargetElement(onlyWith = JDK15OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) private static String sunBootLibraryPath() { String value = ImageSingletons.lookup(SystemPropertiesSupport.class).savedProperties.get("sun.boot.library.path"); return value == null ? "" : value; } @Substitute - @TargetElement(onlyWith = JDK15OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) private static String jdkSerialFilter() { return ImageSingletons.lookup(SystemPropertiesSupport.class).savedProperties.get("jdk.serialFilter"); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_nashorn_api_scripting_ClassFilter.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_nashorn_api_scripting_ClassFilter.java index 61b0d77b3f55..72a3728caa24 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_nashorn_api_scripting_ClassFilter.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_nashorn_api_scripting_ClassFilter.java @@ -27,6 +27,6 @@ import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.jdk.NashornSupport.NashornAvailable; -@TargetClass(className = "jdk.nashorn.api.scripting.ClassFilter", onlyWith = {JDK14OrEarlier.class, NashornAvailable.class}) +@TargetClass(className = "jdk.nashorn.api.scripting.ClassFilter", onlyWith = {JDK11OrEarlier.class, NashornAvailable.class}) public final class Target_jdk_nashorn_api_scripting_ClassFilter { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_nashorn_api_scripting_NashornScriptEngineFactory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_nashorn_api_scripting_NashornScriptEngineFactory.java index 2af6efcd1fc7..31714e6a4649 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_nashorn_api_scripting_NashornScriptEngineFactory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_nashorn_api_scripting_NashornScriptEngineFactory.java @@ -31,7 +31,7 @@ import com.oracle.svm.core.jdk.NashornSupport.NashornAvailable; import com.oracle.svm.core.util.VMError; -@TargetClass(className = "jdk.nashorn.api.scripting.NashornScriptEngineFactory", onlyWith = {JDK14OrEarlier.class, NashornAvailable.class}) +@TargetClass(className = "jdk.nashorn.api.scripting.NashornScriptEngineFactory", onlyWith = {JDK11OrEarlier.class, NashornAvailable.class}) public final class Target_jdk_nashorn_api_scripting_NashornScriptEngineFactory { @Substitute @SuppressWarnings({"unused", "static-method"}) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/ThreadLocalRandomAccessors.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/ThreadLocalRandomAccessors.java index a8bd66da1e57..75671b8a1949 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/ThreadLocalRandomAccessors.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/ThreadLocalRandomAccessors.java @@ -45,7 +45,7 @@ final class Target_java_util_concurrent_ThreadLocalRandom { private static AtomicLong seeder; @Alias - @TargetElement(onlyWith = JDK16OrEarlier.class) + @TargetElement(onlyWith = JDK11OrEarlier.class) static native long mix64(long z); } @@ -72,7 +72,7 @@ public static void setSeeder(AtomicLong value) { @Override long mix64(long l) { - if (JavaVersionUtil.JAVA_SPEC < 17) { + if (JavaVersionUtil.JAVA_SPEC <= 11) { return Target_java_util_concurrent_ThreadLocalRandom.mix64(l); } else { return Target_jdk_internal_util_random_RandomSupport.mixMurmur64(l); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VMErrorSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VMErrorSubstitutions.java index c8dc6da515a5..331f4970b361 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VMErrorSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VMErrorSubstitutions.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.core.jdk; +import static com.oracle.svm.core.annotate.RestrictHeapAccess.Access.NO_ALLOCATION; + import org.graalvm.compiler.nodes.UnreachableNode; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.LogHandler; @@ -39,7 +41,7 @@ import com.oracle.svm.core.snippets.KnownIntrinsics; import com.oracle.svm.core.stack.StackOverflowCheck; import com.oracle.svm.core.stack.ThreadStackPrinter; -import com.oracle.svm.core.thread.VMThreads; +import com.oracle.svm.core.thread.VMThreads.SafepointBehavior; @TargetClass(com.oracle.svm.core.util.VMError.class) final class Target_com_oracle_svm_core_util_VMError { @@ -97,10 +99,13 @@ public class VMErrorSubstitutions { * uninterruptible */ @Uninterruptible(reason = "Allow VMError to be used in uninterruptible code.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate in fatal error handling.", overridesCallers = true) static RuntimeException shouldNotReachHere(CodePointer callerIP, String msg, Throwable ex) { ThreadStackPrinter.printBacktrace(); - VMThreads.StatusSupport.setStatusIgnoreSafepoints(); + + SafepointBehavior.preventSafepoints(); StackOverflowCheck.singleton().disableStackOverflowChecksForFatalError(); + VMErrorSubstitutions.shutdown(callerIP, msg, ex); throw UnreachableNode.unreachable(); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java index 25569ad9e417..d19a0b91920c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java @@ -102,7 +102,7 @@ public class VarHandleFeature implements Feature { private static final Unsafe UNSAFE = GraalUnsafeAccess.getUnsafe(); /** The JDK 11 class VarHandleObjects got renamed to VarHandleReferences. */ - static final String OBJECT_SUFFIX = JavaVersionUtil.JAVA_SPEC > 11 ? "References" : "Objects"; + static final String OBJECT_SUFFIX = JavaVersionUtil.JAVA_SPEC <= 11 ? "Objects" : "References"; private final Map, VarHandleInfo> infos = new HashMap<>(); @@ -489,7 +489,7 @@ final class Target_java_lang_invoke_VarHandle { * collects details about the MemberName, which are method handle internals that must not be * reachable. */ - @TargetElement(onlyWith = JDK14OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) @Substitute @Override public String toString() { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/BundleContentSubstitutedLocalizationSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/BundleContentSubstitutedLocalizationSupport.java index 5a23e72535bf..b46692dd9afd 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/BundleContentSubstitutedLocalizationSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/BundleContentSubstitutedLocalizationSupport.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.jdk.localization; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.ListResourceBundle; @@ -41,6 +42,7 @@ import com.oracle.svm.core.jdk.localization.bundles.StoredBundle; import com.oracle.svm.core.jdk.localization.compression.GzipBundleCompression; import com.oracle.svm.core.util.UserError; +import com.oracle.svm.core.jdk.localization.compression.utils.BundleSerializationUtils; import org.graalvm.compiler.debug.GraalError; // Checkstyle: stop @@ -50,8 +52,6 @@ import sun.util.resources.ParallelListResourceBundle; // Checkstyle: resume -import static com.oracle.svm.core.jdk.localization.compression.utils.BundleSerializationUtils.extractContent; - public class BundleContentSubstitutedLocalizationSupport extends LocalizationSupport { @Platforms(Platform.HOSTED_ONLY.class)// @@ -65,12 +65,17 @@ public class BundleContentSubstitutedLocalizationSupport extends LocalizationSup private final Map, StoredBundle> storedBundles = new ConcurrentHashMap<>(); - public BundleContentSubstitutedLocalizationSupport(Locale defaultLocale, Set locales, List requestedPatterns, ForkJoinPool pool) { - super(defaultLocale, locales); + public BundleContentSubstitutedLocalizationSupport(Locale defaultLocale, Set locales, Charset defaultCharset, List requestedPatterns, ForkJoinPool pool) { + super(defaultLocale, locales, defaultCharset); this.pool = pool; this.compressBundlesPatterns = parseCompressBundlePatterns(requestedPatterns); } + @Override + public boolean substituteLoadLookup() { + return true; + } + @Override @Platforms(Platform.HOSTED_ONLY.class) protected void onBundlePrepared(ResourceBundle bundle) { @@ -95,7 +100,7 @@ private StoredBundle processBundle(ResourceBundle bundle) { if (!isInDefaultLocale && shouldCompressBundle(bundle) && GzipBundleCompression.canCompress(bundle)) { return GzipBundleCompression.compress(bundle); } - Map content = extractContent(bundle); + Map content = BundleSerializationUtils.extractContent(bundle); return new ExtractedBundle(content); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationFeature.java index 61473859ebaf..bf793b3bf4e9 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationFeature.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,519 +24,26 @@ */ package com.oracle.svm.core.jdk.localization; -// Checkstyle: stop - -import java.lang.reflect.Field; -import java.nio.charset.Charset; -import java.nio.charset.UnsupportedCharsetException; -import java.text.spi.BreakIteratorProvider; -import java.text.spi.CollatorProvider; -import java.text.spi.DateFormatProvider; -import java.text.spi.DateFormatSymbolsProvider; -import java.text.spi.DecimalFormatSymbolsProvider; -import java.text.spi.NumberFormatProvider; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.IllformedLocaleException; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.MissingResourceException; -import java.util.Objects; -import java.util.ResourceBundle; -import java.util.Set; -import java.util.concurrent.ForkJoinPool; -import java.util.function.Function; -import java.util.spi.CalendarDataProvider; -import java.util.spi.CalendarNameProvider; -import java.util.spi.CurrencyNameProvider; -import java.util.spi.LocaleNameProvider; -import java.util.spi.LocaleServiceProvider; -import java.util.spi.TimeZoneNameProvider; - -import org.graalvm.collections.Pair; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; -import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin; -import org.graalvm.compiler.options.Option; -import org.graalvm.compiler.options.OptionType; -import org.graalvm.compiler.serviceprovider.JavaVersionUtil; +import com.oracle.svm.core.annotate.AutomaticFeature; +import com.oracle.svm.core.configure.ResourcesRegistry; import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.hosted.Feature; - -import com.oracle.svm.core.ClassLoaderSupport; -import com.oracle.svm.core.annotate.Substitute; -import com.oracle.svm.core.jdk.localization.compression.GzipBundleCompression; -import com.oracle.svm.core.jdk.localization.substitutions.Target_sun_util_locale_provider_LocaleServiceProviderPool_OptimizedLocaleMode; -import com.oracle.svm.core.option.HostedOptionKey; -import com.oracle.svm.core.option.LocatableMultiOptionValue; -import com.oracle.svm.core.option.OptionUtils; -import com.oracle.svm.core.util.UserError; -import com.oracle.svm.core.util.VMError; -import com.oracle.svm.util.ReflectionUtil; - -import jdk.vm.ci.meta.ResolvedJavaField; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; -import sun.util.locale.provider.LocaleProviderAdapter; -import sun.util.locale.provider.ResourceBundleBasedAdapter; -import sun.util.resources.LocaleData; -// Checkstyle: resume +import org.graalvm.nativeimage.impl.ConfigurationCondition; /** - * LocalizationFeature is the core class of SVM localization support. It contains all the options - * that can be used to configure how localization in the resulting image should work. One can - * specify what charsets, locales and resource bundles should be accessible. The runtime data for - * localization is stored in an image singleton of type {@link LocalizationSupport} or one of its - * subtypes. - * - * In case of ResourceBundles, one can also specify how bundles should be handled, because currently - * there are two different modes. - * - * The first approach is using a simple in memory map instead of the original JDK lookup. This - * simpler implementation leads to image size savings for smaller images such as hello world, but - * could cause compatibility issues and maintenance overhead. It is implemented in - * {@link OptimizedLocalizationSupport}. - * - * The second approach relies on the original JVM implementation instead. This approach is - * consistent by design, which solves compatibility issues and reduces maintenance overhead. - * Unfortunately, the default way of storing bundle data in getContents methods, see - * {@link sun.text.resources.FormatData} for example, is not very AOT friendly. Compiling these - * methods is time consuming and results in a bloated image (183 MB HelloWorld with all locales). - * Therefore, the bundle content itself is again stored in the image heap by default and furthermore - * is compressed to reduce the image size, see {@link BundleContentSubstitutedLocalizationSupport} - * and {@link GzipBundleCompression}. - * - * @author d-kozak - * @see LocalizationSupport - * @see OptimizedLocalizationSupport - * @see BundleContentSubstitutedLocalizationSupport + * This class is just a delegate. The real LocalizationFeature is now in + * com.oracle.svm.hosted.jdk.localization. It was created in order to ensure backwards compatibility + * for code depending on the location of the feature. */ -public abstract class LocalizationFeature implements Feature { - - protected final boolean optimizedMode = LocalizationSupport.optimizedMode(); - - private final boolean substituteLoadLookup = Options.LocalizationSubstituteLoadLookup.getValue(); - - protected final boolean trace = Options.TraceLocalizationFeature.getValue(); - - private final ForkJoinPool compressionPool = Options.LocalizationCompressInParallel.getValue() ? new ForkJoinPool(Runtime.getRuntime().availableProcessors()) : null; - - /** - * The Locale that the native image is built for. Currently, switching the Locale at run time is - * not supported because the resource bundles are only included for one Locale. We use the - * Locale that is set for the image generator. - */ - protected Locale defaultLocale = Locale.getDefault(); - - protected Set allLocales; - - protected LocalizationSupport support; - - private Function> findClassByName; - - public static class Options { - @Option(help = "Comma separated list of bundles to be included into the image.", type = OptionType.User)// - public static final HostedOptionKey IncludeResourceBundles = new HostedOptionKey<>(new LocatableMultiOptionValue.Strings()); - - @Option(help = "Make all hosted charsets available at run time")// - public static final HostedOptionKey AddAllCharsets = new HostedOptionKey<>(false); - - @Option(help = "Default locale of the image, by the default it is the same as the default locale of the image builder.", type = OptionType.User)// - public static final HostedOptionKey DefaultLocale = new HostedOptionKey<>(Locale.getDefault().toLanguageTag()); - - @Option(help = "Comma separated list of locales to be included into the image. The default locale is included in the list automatically if not present.", type = OptionType.User)// - public static final HostedOptionKey IncludeLocales = new HostedOptionKey<>(new LocatableMultiOptionValue.Strings()); - - @Option(help = "Make all hosted locales available at run time.", type = OptionType.User)// - public static final HostedOptionKey IncludeAllLocales = new HostedOptionKey<>(false); - - @Option(help = "Optimize the resource bundle lookup using a simple map.", type = OptionType.User)// - public static final HostedOptionKey LocalizationOptimizedMode = new HostedOptionKey<>(JavaVersionUtil.JAVA_SPEC == 8); - - @Option(help = "Store the resource bundle content more efficiently in the fallback mode.", type = OptionType.User)// - public static final HostedOptionKey LocalizationSubstituteLoadLookup = new HostedOptionKey<>(true); - - @Option(help = "Regular expressions matching which bundles should be compressed.", type = OptionType.User)// - public static final HostedOptionKey LocalizationCompressBundles = new HostedOptionKey<>(new LocatableMultiOptionValue.Strings()); - - @Option(help = "Compress the bundles in parallel.", type = OptionType.Expert)// - public static final HostedOptionKey LocalizationCompressInParallel = new HostedOptionKey<>(true); - - @Option(help = "When enabled, localization feature details are printed.", type = OptionType.Debug)// - public static final HostedOptionKey TraceLocalizationFeature = new HostedOptionKey<>(false); - } - - /** - * Many subclasses of {@link Charset} initialize encoding and decoding tables lazily. They all - * follow the same pattern: the methods "initc2b" and/or "initb2c" perform the initialization, - * and then set a field "c2bInitialized" or "b2cInitialized" to true. We run the initialization - * eagerly by creating an encoder and decoder during image generation in - * {@link LocalizationFeature#addCharset}. So we know that the "init*" methods do nothing, and - * we replace calls to them with nothing, i.e,, remove calls to them. - * - * We could do all this with individual {@link Substitute method substitutions}, but it would - * require a lot of substitution methods that all look the same. - */ - public static final class CharsetNodePlugin implements NodePlugin { - - @Override - public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { - if ((method.getName().equals("initc2b") || method.getName().equals("initb2c")) && - b.getMetaAccess().lookupJavaType(Charset.class).isAssignableFrom(method.getDeclaringClass())) { - - /* - * Verify that the "*Initialized" field corresponding with the method was set to - * true, i.e., that initialization was done eagerly. - */ - ResolvedJavaType charsetType = method.getDeclaringClass(); - ResolvedJavaField initializedField = findStaticField(charsetType, method.getName().substring(4, 7) + "Initialized"); - if (!b.getConstantReflection().readFieldValue(initializedField, null).asBoolean()) { - String charsetName = charsetType.getUnqualifiedName(); - try { - Charset charset = Charset.forName(charsetName); - addCharset(charset); - } catch (UnsupportedCharsetException e) { - throw VMError.shouldNotReachHere("Could not find non-initialized charset " + charsetType.getSourceFileName(), e); - } - } - - /* We "handled" the method invocation by doing nothing. */ - return true; - } - return false; - } - - private static ResolvedJavaField findStaticField(ResolvedJavaType declaringClass, String name) { - for (ResolvedJavaField field : declaringClass.getStaticFields()) { - if (field.getName().equals(name)) { - return field; - } - } - throw VMError.shouldNotReachHere(); - } - } - - @Override - public void afterRegistration(AfterRegistrationAccess access) { - findClassByName = access::findClassByName; - allLocales = processLocalesOption(); - defaultLocale = parseLocaleFromTag(Options.DefaultLocale.getValue()); - UserError.guarantee(defaultLocale != null, "Invalid default locale %s", Options.DefaultLocale.getValue()); - allLocales.add(defaultLocale); - support = selectLocalizationSupport(); - ImageSingletons.add(LocalizationSupport.class, support); - ImageSingletons.add(LocalizationFeature.class, this); - - addCharsets(); - if (optimizedMode) { - /* - * Providers are only preprocessed in the optimized mode. - */ - addProviders(); - } - } - - @Platforms(Platform.HOSTED_ONLY.class) - private LocalizationSupport selectLocalizationSupport() { - if (optimizedMode) { - return new OptimizedLocalizationSupport(defaultLocale, allLocales); - } else if (substituteLoadLookup) { - List requestedPatterns = Options.LocalizationCompressBundles.getValue().values(); - return new BundleContentSubstitutedLocalizationSupport(defaultLocale, allLocales, requestedPatterns, compressionPool); - } - return new LocalizationSupport(defaultLocale, allLocales); - } - - @Override - public void beforeAnalysis(BeforeAnalysisAccess access) { - addResourceBundles(); - } - - @Override - public void afterAnalysis(AfterAnalysisAccess access) { - if (compressionPool != null) { - compressionPool.shutdown(); - } - } +@AutomaticFeature +public class LocalizationFeature implements Feature { /** - * @return locale for given tag or null for invalid ones + * @deprecated Use {@link ResourcesRegistry#addResourceBundles(ConfigurationCondition, String)} + * instead. */ - @Platforms(Platform.HOSTED_ONLY.class) - private static Locale parseLocaleFromTag(String tag) { - try { - return new Locale.Builder().setLanguageTag(tag).build(); - } catch (IllformedLocaleException ex) { - /*- Custom made locales consisting of at most three parts separated by '-' are also supported */ - String[] parts = tag.split("-"); - switch (parts.length) { - case 1: - return new Locale(parts[0]); - case 2: - return new Locale(parts[0], parts[1]); - case 3: - return new Locale(parts[0], parts[1], parts[2]); - default: - return null; - } - } - } - - @Platforms(Platform.HOSTED_ONLY.class) - private static Set processLocalesOption() { - Set locales = new HashSet<>(); - if (Options.IncludeAllLocales.getValue()) { - Collections.addAll(locales, Locale.getAvailableLocales()); - /*- Fallthrough to also allow adding custom locales */ - } - List invalid = new ArrayList<>(); - for (String tag : OptionUtils.flatten(",", Options.IncludeLocales.getValue().values())) { - Locale locale = parseLocaleFromTag(tag); - if (locale != null) { - locales.add(locale); - } else { - invalid.add(tag); - } - } - if (!invalid.isEmpty()) { - throw UserError.abort("Invalid locales specified: %s", invalid); - } - return locales; - } - - /** - * The JDK performs dynamic lookup of charsets by name, which leads to dynamic class loading. We - * cannot do that, because we need to know all classes ahead of time to perform our static - * analysis. Therefore, we load and register all standard charsets here. Features that require - * more than this can add additional charsets. - */ - @Platforms(Platform.HOSTED_ONLY.class) - private static void addCharsets() { - if (Options.AddAllCharsets.getValue()) { - for (Charset c : Charset.availableCharsets().values()) { - addCharset(c); - } - } else { - addCharset(Charset.defaultCharset()); - addCharset(Charset.forName("US-ASCII")); - addCharset(Charset.forName("ISO-8859-1")); - addCharset(Charset.forName("UTF-8")); - addCharset(Charset.forName("UTF-16BE")); - addCharset(Charset.forName("UTF-16LE")); - addCharset(Charset.forName("UTF-16")); - } - } - - @Platforms(Platform.HOSTED_ONLY.class) - public static void addCharset(Charset charset) { - Map charsets = ImageSingletons.lookup(LocalizationSupport.class).charsets; - charsets.put(charset.name().toLowerCase(), charset); - for (String name : charset.aliases()) { - charsets.put(name.toLowerCase(), charset); - } - - /* Eagerly initialize all the tables necessary for decoding / encoding. */ - charset.newDecoder(); - if (charset.canEncode()) { - charset.newEncoder(); - } - } - - /* - * LocaleServiceProviderPool.spiClasses does not contain all the classes we need, so we list - * them manually here. - */ - private static final List> spiClasses = Arrays.asList( - BreakIteratorProvider.class, - CollatorProvider.class, - DateFormatProvider.class, - DateFormatSymbolsProvider.class, - DecimalFormatSymbolsProvider.class, - NumberFormatProvider.class, - CurrencyNameProvider.class, - LocaleNameProvider.class, - TimeZoneNameProvider.class, - CalendarDataProvider.class, - CalendarNameProvider.class); - - @Platforms(Platform.HOSTED_ONLY.class) - protected List> getSpiClasses() { - return spiClasses; - } - - @Platforms(Platform.HOSTED_ONLY.class) - private void addProviders() { - OptimizedLocalizationSupport optimizedLocalizationSupport = support.asOptimizedSupport(); - for (Class providerClass : getSpiClasses()) { - LocaleProviderAdapter adapter = Objects.requireNonNull(LocaleProviderAdapter.getAdapter(providerClass, defaultLocale)); - LocaleServiceProvider provider = Objects.requireNonNull(adapter.getLocaleServiceProvider(providerClass)); - optimizedLocalizationSupport.providerPools.put(providerClass, new Target_sun_util_locale_provider_LocaleServiceProviderPool_OptimizedLocaleMode(provider)); - } - - for (Locale locale : allLocales) { - for (Locale candidateLocale : optimizedLocalizationSupport.control.getCandidateLocales("", locale)) { - for (Class providerClass : getSpiClasses()) { - LocaleProviderAdapter adapter = Objects.requireNonNull(LocaleProviderAdapter.getAdapter(providerClass, candidateLocale)); - - optimizedLocalizationSupport.adaptersByClass.put(Pair.create(providerClass, candidateLocale), adapter); - LocaleProviderAdapter existing = optimizedLocalizationSupport.adaptersByType.put(adapter.getAdapterType(), adapter); - assert existing == null || existing == adapter : "Overwriting adapter type with a different adapter"; - - } - } - } - } - - @Platforms(Platform.HOSTED_ONLY.class) - protected void addResourceBundles() { - for (Locale locale : allLocales) { - prepareBundle(localeData(java.util.spi.CalendarDataProvider.class, locale).getCalendarData(locale), locale); - prepareBundle(localeData(java.util.spi.CurrencyNameProvider.class, locale).getCurrencyNames(locale), locale); - prepareBundle(localeData(java.util.spi.LocaleNameProvider.class, locale).getLocaleNames(locale), locale); - prepareBundle(localeData(java.util.spi.TimeZoneNameProvider.class, locale).getTimeZoneNames(locale), locale); - prepareBundle(localeData(java.text.spi.BreakIteratorProvider.class, locale).getBreakIteratorInfo(locale), locale); - prepareBundle(localeData(java.text.spi.BreakIteratorProvider.class, locale).getCollationData(locale), locale); - prepareBundle(localeData(java.text.spi.DateFormatProvider.class, locale).getDateFormatData(locale), locale); - prepareBundle(localeData(java.text.spi.NumberFormatProvider.class, locale).getNumberFormatData(locale), locale); - /* Note that JDK 11 support overrides this method to register more bundles. */ - } - - final String[] alwaysRegisteredResourceBundles = new String[]{ - "sun.util.logging.resources.logging", - "sun.util.resources.TimeZoneNames" - }; - for (String bundleName : alwaysRegisteredResourceBundles) { - prepareBundle(bundleName); - } - - for (String bundleName : OptionUtils.flatten(",", Options.IncludeResourceBundles.getValue())) { - processRequestedBundle(bundleName); - } - } - - @Platforms(Platform.HOSTED_ONLY.class) - protected LocaleData localeData(Class providerClass, Locale locale) { - return ((ResourceBundleBasedAdapter) LocaleProviderAdapter.getAdapter(providerClass, locale)).getLocaleData(); - } - - @Platforms(Platform.HOSTED_ONLY.class) - private void processRequestedBundle(String input) { - int splitIndex = input.indexOf('_'); - boolean specificLocaleRequested = splitIndex != -1; - if (!specificLocaleRequested) { - prepareBundle(input, allLocales); - return; - } - Locale locale = splitIndex + 1 < input.length() ? parseLocaleFromTag(input.substring(splitIndex + 1)) : Locale.ROOT; - if (locale == null) { - trace("Cannot parse wanted locale " + input.substring(splitIndex + 1) + ", default will be used instead."); - locale = defaultLocale; - } - /*- Get rid of locale specific suffix. */ - String baseName = input.substring(0, splitIndex); - prepareBundle(baseName, Collections.singletonList(locale)); - } - - @Platforms(Platform.HOSTED_ONLY.class) + @Deprecated public void prepareBundle(String baseName) { - prepareBundle(baseName, allLocales); - } - - @Platforms(Platform.HOSTED_ONLY.class) - public void prepareBundle(String baseName, Collection wantedLocales) { - if (baseName.isEmpty()) { - return; - } - - boolean somethingFound = false; - for (Locale locale : wantedLocales) { - List resourceBundle; - try { - resourceBundle = ImageSingletons.lookup(ClassLoaderSupport.class).getResourceBundle(baseName, locale); - } catch (MissingResourceException mre) { - continue; - } - somethingFound = !resourceBundle.isEmpty(); - for (ResourceBundle bundle : resourceBundle) { - prepareBundle(baseName, bundle, locale); - } - } - - if (!somethingFound) { - /* - * Try non-compliant class-based bundles. These bundles can't be looked up by the normal - * ResourceBundle lookup process, e.g. because they don't have default constructors. - */ - Class clazz = findClassByName.apply(baseName); - if (clazz != null && ResourceBundle.class.isAssignableFrom(clazz)) { - trace("Found non-compliant class-based bundle " + clazz); - somethingFound = true; - support.prepareNonCompliant(clazz); - } - } - - if (!somethingFound) { - String errorMessage = "The bundle named: " + baseName + ", has not been found. " + - "If the bundle is part of a module, verify the bundle name is a fully qualified class name. Otherwise " + - "verify the bundle path is accessible in the classpath."; - // Checkstyle: stop - System.out.println(errorMessage); - // Checkstyle: resume - } - } - - @Platforms(Platform.HOSTED_ONLY.class) - protected void prepareBundle(ResourceBundle bundle, Locale locale) { - prepareBundle(bundle.getBaseBundleName(), bundle, locale); - } - - @Platforms(Platform.HOSTED_ONLY.class) - private void prepareBundle(String bundleName, ResourceBundle bundle, Locale locale) { - trace("Adding bundle " + bundleName + ", locale " + locale); - /* - * Ensure that the bundle contents are loaded. We need to walk the whole bundle parent chain - * down to the root. - */ - for (ResourceBundle cur = bundle; cur != null; cur = getParent(cur)) { - /* Register all bundles with their corresponding locales */ - support.prepareBundle(bundleName, cur, cur.getLocale()); - } - - /* - * Finally, register the requested bundle with requested locale (Requested might be more - * specific than the actual bundle locale - */ - support.prepareBundle(bundleName, bundle, locale); - } - - /* - * The field ResourceBundle.parent is not public. There is a backdoor to access it via - * SharedSecrets, but the package of SharedSecrets changed from JDK 8 to JDK 11 so it is - * inconvenient to use it. Reflective access is easier. - */ - private static final Field PARENT_FIELD = ReflectionUtil.lookupField(ResourceBundle.class, "parent"); - - @Platforms(Platform.HOSTED_ONLY.class) - private static ResourceBundle getParent(ResourceBundle bundle) { - try { - return (ResourceBundle) PARENT_FIELD.get(bundle); - } catch (ReflectiveOperationException ex) { - throw VMError.shouldNotReachHere(ex); - } - } - - @Platforms(Platform.HOSTED_ONLY.class) - protected void trace(String msg) { - if (trace) { - // Checkstyle: stop - System.out.println(msg); - // Checkstyle: resume - } + ImageSingletons.lookup(ResourcesRegistry.class).addResourceBundles(ConfigurationCondition.alwaysTrue(), baseName); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationSupport.java index cd601c0dcc46..cca533de556c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationSupport.java @@ -34,7 +34,6 @@ import java.util.Set; import java.util.stream.Collectors; -import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.debug.GraalError; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; @@ -49,7 +48,7 @@ * Holder for localization information that is computed during image generation and used at run * time. * - * @see LocalizationFeature + * For more details, see LocalizationFeature */ public class LocalizationSupport { @@ -63,22 +62,27 @@ public class LocalizationSupport { public final ResourceBundle.Control control = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT); - public LocalizationSupport(Locale defaultLocale, Set locales) { + public final Charset defaultCharset; + + public LocalizationSupport(Locale defaultLocale, Set locales, Charset defaultCharset) { this.defaultLocale = defaultLocale; this.allLocales = locales.toArray(new Locale[0]); + this.defaultCharset = defaultCharset; this.supportedLanguageTags = locales.stream().map(Locale::toString).collect(Collectors.toSet()); } - @Fold - public static boolean optimizedMode() { - return LocalizationFeature.Options.LocalizationOptimizedMode.getValue(); + public boolean optimizedMode() { + return false; } - @Fold - public static boolean jvmMode() { + public boolean jvmMode() { return !optimizedMode(); } + public boolean substituteLoadLookup() { + return false; + } + public OptimizedLocalizationSupport asOptimizedSupport() { GraalError.guarantee(optimizedMode(), "Optimized support only available in optimized localization mode."); return ((OptimizedLocalizationSupport) this); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/OptimizedLocalizationSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/OptimizedLocalizationSupport.java index 0ce86b49d2ea..68474bb2e938 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/OptimizedLocalizationSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/OptimizedLocalizationSupport.java @@ -24,9 +24,9 @@ */ package com.oracle.svm.core.jdk.localization; -import com.oracle.svm.core.option.SubstrateOptionsParser; import org.graalvm.collections.Pair; +import java.nio.charset.Charset; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -48,10 +48,13 @@ public class OptimizedLocalizationSupport extends LocalizationSupport { final Map, ResourceBundle> resourceBundles = new HashMap<>(); - private final String includeResourceBundlesOption = SubstrateOptionsParser.commandArgument(LocalizationFeature.Options.IncludeResourceBundles, ""); + public OptimizedLocalizationSupport(Locale defaultLocale, Set locales, Charset defaultCharset) { + super(defaultLocale, locales, defaultCharset); + } - public OptimizedLocalizationSupport(Locale defaultLocale, Set locales) { - super(defaultLocale, locales); + @Override + public boolean optimizedMode() { + return true; } /** @@ -68,7 +71,7 @@ public ResourceBundle getCached(String baseName, Locale locale) throws MissingRe } } String errorMessage = "Resource bundle not found " + baseName + ", locale " + locale + ". " + - "Register the resource bundle using the option " + includeResourceBundlesOption + baseName + "."; + "Register the resource bundle using the option -H:IncludeResourceBundles=" + baseName + "."; throw new MissingResourceException(errorMessage, this.getClass().getName(), baseName); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/Target_java_nio_charset_Charset.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/Target_java_nio_charset_Charset.java index 1f3b52c8ddbd..47ee22a10192 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/Target_java_nio_charset_Charset.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/Target_java_nio_charset_Charset.java @@ -42,15 +42,9 @@ @SuppressWarnings({"unused"}) final class Target_java_nio_charset_Charset { - @Alias private static Charset defaultCharset; - @Substitute private static Charset defaultCharset() { - /* - * The default charset is initialized during native image generation and therefore always - * available without any checks. - */ - return defaultCharset; + return ImageSingletons.lookup(LocalizationSupport.class).defaultCharset; } @Substitute diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/Target_sun_util_locale_provider_LocaleServiceProviderPool_OptimizedLocaleMode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/Target_sun_util_locale_provider_LocaleServiceProviderPool_OptimizedLocaleMode.java index 6798bf245fd9..fa3d5b946f97 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/Target_sun_util_locale_provider_LocaleServiceProviderPool_OptimizedLocaleMode.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/Target_sun_util_locale_provider_LocaleServiceProviderPool_OptimizedLocaleMode.java @@ -28,8 +28,8 @@ import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.annotate.TargetElement; +import com.oracle.svm.core.jdk.JDK11OrEarlier; import com.oracle.svm.core.jdk.JDK11OrLater; -import com.oracle.svm.core.jdk.JDK11To14; import com.oracle.svm.core.jdk.JDK8OrEarlier; import com.oracle.svm.core.jdk.localization.LocalizationSupport; import com.oracle.svm.core.jdk.localization.substitutions.modes.OptimizedLocaleMode; @@ -94,7 +94,7 @@ public native

    S getLocalizedObject(LocaleSe Object... params); @KeepOriginal // - @TargetElement(onlyWith = JDK11To14.class) // + @TargetElement(onlyWith = {JDK11OrLater.class, JDK11OrEarlier.class}) // static native void config(Class caller, String message); @Substitute diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/modes/JvmLocaleMode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/modes/JvmLocaleMode.java index 47946f6de718..98db7778ed07 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/modes/JvmLocaleMode.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/modes/JvmLocaleMode.java @@ -26,6 +26,7 @@ import java.util.function.BooleanSupplier; +import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -35,6 +36,6 @@ public class JvmLocaleMode implements BooleanSupplier { @Override public boolean getAsBoolean() { - return LocalizationSupport.jvmMode(); + return ImageSingletons.lookup(LocalizationSupport.class).jvmMode(); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/modes/OptimizedLocaleMode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/modes/OptimizedLocaleMode.java index 4a824d4549e9..1ef9e78fef70 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/modes/OptimizedLocaleMode.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/modes/OptimizedLocaleMode.java @@ -27,10 +27,11 @@ import java.util.function.BooleanSupplier; import com.oracle.svm.core.jdk.localization.LocalizationSupport; +import org.graalvm.nativeimage.ImageSingletons; public class OptimizedLocaleMode implements BooleanSupplier { @Override public boolean getAsBoolean() { - return LocalizationSupport.optimizedMode(); + return ImageSingletons.lookup(LocalizationSupport.class).optimizedMode(); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/modes/SubstituteLoadLookup.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/modes/SubstituteLoadLookup.java index 06ae2a19cdaf..a29d643342e0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/modes/SubstituteLoadLookup.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/modes/SubstituteLoadLookup.java @@ -26,10 +26,10 @@ import java.util.function.Predicate; +import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; -import com.oracle.svm.core.jdk.localization.LocalizationFeature; import com.oracle.svm.core.jdk.localization.LocalizationSupport; @Platforms(Platform.HOSTED_ONLY.class) @@ -37,7 +37,8 @@ public class SubstituteLoadLookup implements Predicate { @Override public boolean test(String className) { - return LocalizationSupport.optimizedMode() || LocalizationFeature.Options.LocalizationSubstituteLoadLookup.getValue(); + LocalizationSupport support = ImageSingletons.lookup(LocalizationSupport.class); + return support.optimizedMode() || support.substituteLoadLookup(); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/SubstrateOperatingSystemMXBean.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/SubstrateOperatingSystemMXBean.java index 4261147b9519..c6a53cd86459 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/SubstrateOperatingSystemMXBean.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/SubstrateOperatingSystemMXBean.java @@ -70,7 +70,7 @@ public int getAvailableProcessors() { return Runtime.getRuntime().availableProcessors(); } - @SuppressWarnings("deprecation") // getTotalPhysicalMemorySize deprecated since JDK 14 + @SuppressWarnings("deprecation") // getTotalPhysicalMemorySize is deprecated after JDK 11 @Override public long getTotalPhysicalMemorySize() { return PhysicalMemory.size().rawValue(); @@ -101,13 +101,13 @@ public long getProcessCpuTime() { throw VMError.unsupportedFeature(MSG); } - @SuppressWarnings("deprecation") // getFreePhysicalMemorySize deprecated since JDK 14 + @SuppressWarnings("deprecation") // getFreePhysicalMemorySize is deprecated after JDK 11 @Override public long getFreePhysicalMemorySize() { throw VMError.unsupportedFeature(MSG); } - @SuppressWarnings("deprecation") // getSystemCpuLoad deprecated since JDK 14 + @SuppressWarnings("deprecation") // getSystemCpuLoad is deprecated after JDK 11 @Override public double getSystemCpuLoad() { throw VMError.unsupportedFeature(MSG); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/SubstrateOperatingSystemMXBeanBase.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/SubstrateOperatingSystemMXBeanBase.java index 3ddc68935c62..dab9ceccd728 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/SubstrateOperatingSystemMXBeanBase.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/SubstrateOperatingSystemMXBeanBase.java @@ -27,7 +27,7 @@ import com.oracle.svm.core.util.VMError; /** - * Base class for defining methods introduced in JDK 14 by JDK-8226575. + * Base class for defining methods introduced after JDK 11 by JDK-8226575. * * Putting these in a class that does not implement {@link com.sun.management.OperatingSystemMXBean} * avoids javac errors related these methods being annotated by {@link Override}. @@ -35,7 +35,6 @@ public abstract class SubstrateOperatingSystemMXBeanBase { static final String MSG = "OperatingSystemMXBean methods"; - // Temporary fix for JDK14 added methods. // Will be removed after [GR-20166] is implemented. public double getCpuLoad() { throw VMError.unsupportedFeature(MSG); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/resources/NativeImageResourcePath.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/resources/NativeImageResourcePath.java index 3c7bccdd5bac..f3a3b4b4a0de 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/resources/NativeImageResourcePath.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/resources/NativeImageResourcePath.java @@ -603,13 +603,13 @@ private byte[] getResolved() { } for (byte c : path) { if (c == '.') { - return doGetResolved(this); + return getResolved(this); } } return path; } - private static byte[] doGetResolved(NativeImageResourcePath p) { + public static byte[] getResolved(NativeImageResourcePath p) { int nc = p.getNameCount(); byte[] path = p.path; int[] offsets = p.offsets; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/resources/ResourceURLConnection.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/resources/ResourceURLConnection.java index 3aa271c5f30d..8733cd70f25c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/resources/ResourceURLConnection.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/resources/ResourceURLConnection.java @@ -63,7 +63,7 @@ public void connect() { connected = true; String resourceName = resolveName(url.getPath()); - ResourceStorageEntry entry = Resources.get(resourceName); + ResourceStorageEntry entry = Resources.get(Resources.toCanonicalForm(resourceName)); if (entry != null) { List bytes = entry.getData(); if (index < bytes.size()) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java index 04fc1fa38d78..558def22f7aa 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java @@ -100,7 +100,7 @@ public class MultiThreadedMonitorSupport extends MonitorSupport { * This is only used for preempting a continuation in the experimental Loom JDK support. There's * performance impact in this solution. */ - protected static final FastThreadLocalInt lockedMonitors = FastThreadLocalFactory.createInt(); + protected static final FastThreadLocalInt lockedMonitors = FastThreadLocalFactory.createInt("MultiThreadedMonitorSupport.lockedMonitors"); protected static void onMonitorLocked() { if (JavaContinuations.useLoom()) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/HostedOptionKey.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/HostedOptionKey.java index 70c23993eec9..4816367709d2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/HostedOptionKey.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/HostedOptionKey.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.core.option; +import com.oracle.svm.common.option.LocatableOption; +import com.oracle.svm.common.option.MultiOptionValue; import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.options.Option; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/LocatableMultiOptionValue.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/LocatableMultiOptionValue.java index bf43136b21d2..176087b6115f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/LocatableMultiOptionValue.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/LocatableMultiOptionValue.java @@ -29,6 +29,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import com.oracle.svm.common.option.LocatableOption; +import com.oracle.svm.common.option.MultiOptionValue; import org.graalvm.collections.Pair; import com.oracle.svm.core.util.VMError; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/RuntimeOptionParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/RuntimeOptionParser.java index ff5a104b6fe2..aa4ec3eab602 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/RuntimeOptionParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/RuntimeOptionParser.java @@ -39,10 +39,10 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; +import com.oracle.svm.common.option.CommonOptionParser.BooleanOptionFormat; +import com.oracle.svm.common.option.CommonOptionParser.OptionParseResult; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.log.Log; -import com.oracle.svm.core.option.SubstrateOptionsParser.BooleanOptionFormat; -import com.oracle.svm.core.option.SubstrateOptionsParser.OptionParseResult; import com.oracle.svm.core.properties.RuntimePropertyParser; import com.oracle.svm.core.util.ImageHeapMap; @@ -163,7 +163,8 @@ private void parseOptionAtRuntime(String arg, String optionPrefix, BooleanOption Predicate> isHosted = optionKey -> false; OptionParseResult parseResult = SubstrateOptionsParser.parseOption(options, isHosted, arg.substring(optionPrefix.length()), values, optionPrefix, booleanOptionFormat); if (parseResult.printFlags() || parseResult.printFlagsWithExtraHelp()) { - SubstrateOptionsParser.printFlags(parseResult::matchesFlagsRuntime, options, optionPrefix, Log.logStream(), parseResult.printFlagsWithExtraHelp()); + SubstrateOptionsParser.printFlags(d -> parseResult.matchesFlags(d, d.getOptionKey() instanceof RuntimeOptionKey), + options, optionPrefix, Log.logStream(), parseResult.printFlagsWithExtraHelp()); System.exit(0); } if (!parseResult.isValid()) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/SubstrateOptionsParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/SubstrateOptionsParser.java index f049bd43c7e9..f6144bfd437b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/SubstrateOptionsParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/SubstrateOptionsParser.java @@ -28,29 +28,25 @@ import java.io.PrintStream; import java.lang.reflect.Field; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Comparator; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.List; +import java.util.ServiceLoader; import java.util.Set; import java.util.function.Consumer; import java.util.function.Predicate; import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.options.OptionDescriptor; +import org.graalvm.compiler.options.OptionDescriptors; import org.graalvm.compiler.options.OptionKey; -import org.graalvm.compiler.options.OptionType; -import org.graalvm.compiler.options.OptionsParser; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.SubstrateUtil; +import com.oracle.svm.common.option.CommonOptionParser; +import com.oracle.svm.common.option.CommonOptionParser.BooleanOptionFormat; +import com.oracle.svm.common.option.CommonOptionParser.OptionParseResult; +import com.oracle.svm.common.option.UnsupportedOptionClassException; import com.oracle.svm.core.util.InterruptImageBuilding; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.util.ClassUtil; /** * This class contains methods for parsing options and matching them against @@ -58,283 +54,17 @@ */ public class SubstrateOptionsParser { - public static final String HOSTED_OPTION_PREFIX = "-H:"; - public static final String RUNTIME_OPTION_PREFIX = "-R:"; - public static final int PRINT_OPTION_INDENTATION = 2; - public static final int PRINT_OPTION_WIDTH = 45; - public static final int PRINT_OPTION_WRAP_WIDTH = 120; - - /** - * The result of {@link SubstrateOptionsParser#parseOption}. - */ - static final class OptionParseResult { - private final EnumSet printFlags; - private final Set optionNameFilter; - private final String error; - private final OptionKey optionKey; - private static final String EXTRA_HELP_OPTIONS_WILDCARD = "*"; - - private OptionParseResult(EnumSet printFlags, String error, Set optionNameFilter, OptionKey optionKey) { - this.printFlags = printFlags; - this.error = error; - this.optionNameFilter = optionNameFilter; - this.optionKey = optionKey; - } - - private OptionParseResult(EnumSet printFlags, String error, OptionKey optionKey) { - this(printFlags, error, new HashSet<>(), optionKey); - } - - static OptionParseResult error(String message) { - return new OptionParseResult(EnumSet.noneOf(OptionType.class), message, null); - } - - static OptionParseResult correct(OptionKey optionKey) { - return new OptionParseResult(EnumSet.noneOf(OptionType.class), null, optionKey); - } - - static OptionParseResult printFlags(EnumSet selectedOptionTypes) { - return new OptionParseResult(selectedOptionTypes, null, null); - } - - static OptionParseResult printFlagsWithExtraHelp(Set optionNameFilter) { - Set optionNames = optionNameFilter; - if (optionNames.contains(EXTRA_HELP_OPTIONS_WILDCARD)) { - optionNames = new HashSet<>(); - optionNames.add(EXTRA_HELP_OPTIONS_WILDCARD); - } - return new OptionParseResult(EnumSet.noneOf(OptionType.class), null, optionNames, null); - } - - boolean printFlags() { - return !printFlags.isEmpty(); - } - - boolean printFlagsWithExtraHelp() { - return !optionNameFilter.isEmpty(); - } - - public boolean isValid() { - boolean result = optionKey != null; - assert result == (printFlags.isEmpty() && optionNameFilter.isEmpty() && error == null); - return result; - } - - public String getError() { - return error; - } - - public OptionKey getOptionKey() { - return optionKey; - } - - private boolean matchesFlags(OptionDescriptor d, boolean svmOption) { - if (!printFlags.isEmpty()) { - boolean showAll = printFlags.equals(EnumSet.allOf(OptionType.class)); - return showAll || svmOption && printFlags.contains(d.getOptionType()); - } - if (!optionNameFilter.isEmpty()) { - if (optionNameFilter.contains(EXTRA_HELP_OPTIONS_WILDCARD) && !d.getExtraHelp().isEmpty()) { - return true; - } - return optionNameFilter.contains(d.getName()); - } - return false; - } - - boolean matchesFlagsRuntime(OptionDescriptor d) { - return matchesFlags(d, d.getOptionKey() instanceof RuntimeOptionKey); - } - - boolean matchesFlagsHosted(OptionDescriptor d) { - OptionKey key = d.getOptionKey(); - return matchesFlags(d, key instanceof RuntimeOptionKey || key instanceof HostedOptionKey); - } - } - - /** - * Constants denoting supported boolean option formats. - */ - public enum BooleanOptionFormat { - NAME_VALUE("="), - PLUS_MINUS("+/-"); - - BooleanOptionFormat(String help) { - this.help = help; - } - - private final String help; - - @Override - public String toString() { - return help; - } - } + public static final String HOSTED_OPTION_PREFIX = CommonOptionParser.HOSTED_OPTION_PREFIX; + public static final String RUNTIME_OPTION_PREFIX = CommonOptionParser.RUNTIME_OPTION_PREFIX; static OptionParseResult parseOption(EconomicMap options, Predicate> isHosted, String option, EconomicMap, Object> valuesMap, String optionPrefix, BooleanOptionFormat booleanOptionFormat) { - if (option.length() == 0) { - return OptionParseResult.error("Option name must be specified"); - } - - String optionName; - Object value = null; - String valueString = null; - - char first = option.charAt(0); - int eqIndex = option.indexOf('='); - if (first == '+' || first == '-') { - if (eqIndex != -1) { - return OptionParseResult.error("Cannot mix +/- with = format: '" + optionPrefix + option + "'"); - } - optionName = option.substring(1); - if (booleanOptionFormat == BooleanOptionFormat.NAME_VALUE) { - return OptionParseResult.error("Option " + LocatableOption.from(optionName) + " must use = format, not +/- prefix"); - } - value = (first == '+'); - } else { - if (eqIndex == -1) { - optionName = option; - valueString = null; - } else { - optionName = option.substring(0, eqIndex); - valueString = option.substring(eqIndex + 1); - } - } - - LocatableOption current = LocatableOption.from(optionName); - OptionDescriptor desc = options.get(current.name); - if (desc == null && value != null) { - if (eqIndex != -1) { - optionName = option.substring(1, eqIndex); - current = LocatableOption.from(optionName); - desc = options.get(current.name); - } - } - - optionName = current.name; - - if (desc == null) { - List matches = new ArrayList<>(); - OptionsParser.collectFuzzyMatches(options.getValues(), optionName, matches); - StringBuilder msg = new StringBuilder("Could not find option ").append(current); - if (!matches.isEmpty()) { - msg.append(". Did you mean one of these:"); - for (OptionDescriptor match : matches) { - msg.append(' ').append(match.getName()); - } - } - msg.append(". Use ").append(optionPrefix).append(SubstrateOptions.PrintFlags.getName()).append("= to list all available options."); - return OptionParseResult.error(msg.toString()); - } - - OptionKey optionKey = desc.getOptionKey(); - boolean hostedOption = isHosted.test(optionKey); - Class optionValueType = getMultiOptionValueElementType(optionKey); - Class optionType = hostedOption && optionValueType != null ? optionValueType : desc.getOptionValueType(); - - if (value == null) { - if (optionType == Boolean.class && booleanOptionFormat == BooleanOptionFormat.PLUS_MINUS) { - return OptionParseResult.error("Boolean option " + current + " must have +/- prefix"); - } - if (valueString == null) { - return OptionParseResult.error("Missing value for option " + current); - } - try { - value = parseValue(optionType, current, valueString); - if (value instanceof OptionParseResult) { - return (OptionParseResult) value; - } - } catch (NumberFormatException ex) { - return OptionParseResult.error("Invalid value for option " + current + ": '" + valueString + "' is not a valid number"); - } - } else { - if (optionType != Boolean.class) { - return OptionParseResult.error("Non-boolean option " + current + " can not use +/- prefix. Use '" + current.name + "=' format"); - } - } - - optionKey.update(valuesMap, hostedOption ? LocatableOption.value(value, current.origin) : value); - - if (SubstrateOptions.PrintFlags.getName().equals(optionName)) { - String optionValue = (String) value; - EnumSet selectedOptionTypes; - if (optionValue.isEmpty()) { - selectedOptionTypes = EnumSet.allOf(OptionType.class); - } else { - selectedOptionTypes = EnumSet.noneOf(OptionType.class); - String enumString = null; - try { - String[] enumStrings = SubstrateUtil.split(optionValue, ","); - - for (String string : enumStrings) { - enumString = string; - selectedOptionTypes.add(OptionType.valueOf(enumString)); - } - } catch (IllegalArgumentException e) { - StringBuilder sb = new StringBuilder(); - boolean firstValue = true; - for (OptionType ot : OptionType.values()) { - if (firstValue) { - firstValue = false; - } else { - sb.append(", "); - } - sb.append(ot.name()); - } - String possibleValues = sb.toString(); - return OptionParseResult.error("Invalid value for option " + current + ". '" + enumString + "' is not one of: " + possibleValues); - } - } - return OptionParseResult.printFlags(selectedOptionTypes); - } - if (SubstrateOptions.PrintFlagsWithExtraHelp.getName().equals(optionName)) { - String optionValue = (String) value; - String[] optionNames = SubstrateUtil.split(optionValue, ","); - HashSet selectedOptionNames = new HashSet<>(Arrays.asList(optionNames)); - return OptionParseResult.printFlagsWithExtraHelp(selectedOptionNames); - } - - return OptionParseResult.correct(optionKey); - } - - private static Class getMultiOptionValueElementType(OptionKey optionKey) { - Object defaultValue = optionKey.getDefaultValue(); - if (defaultValue instanceof MultiOptionValue) { - return ((MultiOptionValue) defaultValue).getValueType(); - } - return null; - } - - @SuppressWarnings("unchecked") - static Object parseValue(Class optionType, LocatableOption option, String valueString) throws NumberFormatException { - Object value; - if (optionType == Integer.class) { - long longValue = parseLong(valueString); - if ((int) longValue != longValue) { - return OptionParseResult.error("Wrong value for option " + option + ": '" + valueString + "' is not a valid number"); - } - value = (int) longValue; - } else if (optionType == Long.class) { - value = parseLong(valueString); - } else if (optionType == String.class) { - value = valueString; - } else if (optionType == Double.class) { - value = parseDouble(valueString); - } else if (optionType == Boolean.class) { - if (valueString.equals("true")) { - value = true; - } else if (valueString.equals("false")) { - value = false; - } else { - return OptionParseResult.error("Boolean option " + option + " must have value 'true' or 'false'"); - } - } else if (optionType.isEnum()) { - value = Enum.valueOf(optionType.asSubclass(Enum.class), valueString); - } else { - throw VMError.shouldNotReachHere(option + " uses unsupported option value class: " + ClassUtil.getUnqualifiedName(optionType)); + try { + return CommonOptionParser.parseOption(options, isHosted, option, valuesMap, optionPrefix, booleanOptionFormat); + } catch (UnsupportedOptionClassException e) { + VMError.shouldNotReachHere(e.getMessage()); + return null; } - return value; } /** @@ -359,7 +89,10 @@ public static boolean parseHostedOption(String optionPrefix, EconomicMap { + OptionKey key = d.getOptionKey(); + return optionParseResult.matchesFlags(d, key instanceof RuntimeOptionKey || key instanceof HostedOptionKey); + }, options, optionPrefix, out, optionParseResult.printFlagsWithExtraHelp()); throw new InterruptImageBuilding(""); } if (!optionParseResult.isValid()) { @@ -383,46 +116,12 @@ public static boolean parseHostedOption(String optionPrefix, EconomicMap optionDescriptors, Consumer optionDescriptorConsumer) { + CommonOptionParser.collectOptions(optionDescriptors, optionDescriptorConsumer); } public static void printOption(Consumer println, String option, String description, int indentation, int optionWidth, int wrapWidth) { - String indent = spaces(indentation); - String desc = description != null ? description : ""; - desc = wrapWidth > 0 ? wrap(desc, wrapWidth) : desc; - String nl = System.lineSeparator(); - String[] descLines = SubstrateUtil.split(desc, nl); - if (option.length() >= optionWidth && description != null) { - println.accept(indent + option + nl + indent + spaces(optionWidth) + descLines[0]); - } else { - println.accept(indent + option + spaces(optionWidth - option.length()) + descLines[0]); - } - for (int i = 1; i < descLines.length; i++) { - println.accept(indent + spaces(optionWidth) + descLines[i]); - } + CommonOptionParser.printOption(println, option, description, indentation, optionWidth, wrapWidth); } /** @@ -441,151 +140,15 @@ public static void printOption(Consumer println, String option, String d * between space and execution efficiency is acceptable. */ static void printFlags(Predicate filter, EconomicMap options, String prefix, PrintStream out, boolean verbose) { - List sortedDescriptors = new ArrayList<>(); - for (OptionDescriptor option : options.getValues()) { - if (filter.test(option)) { - sortedDescriptors.add(option); - } - } - sortedDescriptors.sort(Comparator.comparing(OptionDescriptor::getName)); - - for (OptionDescriptor descriptor : sortedDescriptors) { - String helpMsg = verbose && !descriptor.getExtraHelp().isEmpty() ? "" : descriptor.getHelp(); - int helpLen = helpMsg.length(); - if (helpLen > 0 && helpMsg.charAt(helpLen - 1) != '.') { - helpMsg += '.'; - } - boolean stringifiedArrayValue = false; - Object defaultValue = descriptor.getOptionKey().getDefaultValue(); - if (defaultValue != null && defaultValue.getClass().isArray()) { - Object[] defaultValues = (Object[]) defaultValue; - if (defaultValues.length == 1) { - defaultValue = defaultValues[0]; - } else { - List stringList = new ArrayList<>(); - String optionPrefix = prefix + descriptor.getName() + "="; - for (Object rawValue : defaultValues) { - String value; - if (rawValue instanceof String) { - value = '"' + String.valueOf(rawValue) + '"'; - } else { - value = String.valueOf(rawValue); - } - stringList.add(optionPrefix + value); - } - if (helpLen != 0) { - helpMsg += ' '; - } - helpMsg += "Default: "; - if (stringList.isEmpty()) { - helpMsg += "None"; - } else { - helpMsg += String.join(" ", stringList); - } - stringifiedArrayValue = true; - } - } - String verboseHelp = ""; - if (verbose) { - verboseHelp = System.lineSeparator() + descriptor.getHelp() + System.lineSeparator() + String.join(System.lineSeparator(), descriptor.getExtraHelp()); - } else if (!descriptor.getExtraHelp().isEmpty()) { - verboseHelp = " [Extra help available]"; - } - int wrapWidth = verbose ? 0 : PRINT_OPTION_WRAP_WIDTH; - if (descriptor.getOptionValueType() == Boolean.class) { - Boolean val = (Boolean) defaultValue; - if (helpLen != 0) { - helpMsg += ' '; - } - if (val != null) { - if (val) { - helpMsg += "Default: + (enabled)."; - } else { - helpMsg += "Default: - (disabled)."; - } - } - printOption(out, prefix + "\u00b1" + descriptor.getName(), helpMsg + verboseHelp, wrapWidth); - } else { - if (defaultValue == null) { - if (helpLen != 0) { - helpMsg += ' '; - } - helpMsg += "Default: None"; - } - helpMsg += verboseHelp; - if (stringifiedArrayValue || defaultValue == null) { - printOption(out, prefix + descriptor.getName() + "=...", helpMsg, wrapWidth); - } else { - if (defaultValue instanceof String) { - defaultValue = '"' + String.valueOf(defaultValue) + '"'; - } - printOption(out, prefix + descriptor.getName() + "=" + defaultValue, helpMsg, wrapWidth); - } - } - } + CommonOptionParser.printFlags(filter, options, prefix, out, verbose); } public static long parseLong(String v) { - String valueString = v.trim().toLowerCase(); - long scale = 1; - if (valueString.endsWith("k")) { - scale = 1024L; - } else if (valueString.endsWith("m")) { - scale = 1024L * 1024L; - } else if (valueString.endsWith("g")) { - scale = 1024L * 1024L * 1024L; - } else if (valueString.endsWith("t")) { - scale = 1024L * 1024L * 1024L * 1024L; - } - - if (scale != 1) { - /* Remove trailing scale character. */ - valueString = valueString.substring(0, valueString.length() - 1); - } - - return Long.parseLong(valueString) * scale; + return CommonOptionParser.parseLong(v); } - /** - * Parses the provide string to a double number, avoiding the JDK dependencies (which pull in a - * lot of classes, including the regular expression library). Only simple numbers are supported, - * without fancy exponent styles. - */ public static double parseDouble(String v) { - String valueString = v.trim(); - - int dotPos = valueString.indexOf('.'); - if (dotPos == -1) { - return parseLong(valueString); - } - - String beforeDot = valueString.substring(0, dotPos); - String afterDot = valueString.substring(dotPos + 1); - - double sign = 1; - if (beforeDot.startsWith("-")) { - sign = -1; - beforeDot = beforeDot.substring(1); - } else if (beforeDot.startsWith("+")) { - beforeDot = beforeDot.substring(1); - } - - if (beforeDot.startsWith("-") || beforeDot.startsWith("+") || afterDot.startsWith("-") || afterDot.startsWith("+") || - (beforeDot.length() == 0 && afterDot.length() == 0)) { - throw new NumberFormatException(v); - } - - double integral = 0; - if (beforeDot.length() > 0) { - integral = Long.parseLong(beforeDot); - } - - double fraction = 0; - if (afterDot.length() > 0) { - fraction = Long.parseLong(afterDot) * Math.pow(10, -afterDot.length()); - } - - return sign * (integral + fraction); + return CommonOptionParser.parseDouble(v); } /** diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCommittedMemoryProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCommittedMemoryProvider.java index 3acca7f3f2dd..87412abf2579 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCommittedMemoryProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCommittedMemoryProvider.java @@ -48,6 +48,39 @@ public boolean guaranteesHeapPreferredAddressSpaceAlignment() { return SubstrateOptions.SpawnIsolates.getValue() && ImageHeapProvider.get().guaranteesHeapPreferredAddressSpaceAlignment(); } + @Override + public Pointer allocateAlignedChunk(UnsignedWord nbytes, UnsignedWord alignment) { + return allocate(nbytes, alignment, false); + } + + @Override + public Pointer allocateUnalignedChunk(UnsignedWord nbytes) { + return allocate(nbytes, CommittedMemoryProvider.UNALIGNED, false); + } + + @Override + public Pointer allocateExecutableMemory(UnsignedWord nbytes, UnsignedWord alignment) { + return allocate(nbytes, alignment, true); + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public void freeAlignedChunk(PointerBase start, UnsignedWord nbytes, UnsignedWord alignment) { + free(start, nbytes, alignment, false); + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public void freeUnalignedChunk(PointerBase start, UnsignedWord nbytes) { + free(start, nbytes, CommittedMemoryProvider.UNALIGNED, false); + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public void freeExecutableMemory(PointerBase start, UnsignedWord nbytes, UnsignedWord alignment) { + free(start, nbytes, alignment, true); + } + @Uninterruptible(reason = "Still being initialized.") protected static int protectSingleIsolateImageHeap() { assert !SubstrateOptions.SpawnIsolates.getValue() : "Must be handled by ImageHeapProvider when SpawnIsolates is enabled"; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/CommittedMemoryProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/CommittedMemoryProvider.java index 5c982b45b59b..1782f18eb5c5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/CommittedMemoryProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/CommittedMemoryProvider.java @@ -26,6 +26,7 @@ import java.util.EnumSet; +import com.oracle.svm.core.util.VMError; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.c.type.WordPointer; @@ -99,7 +100,23 @@ default UnsignedWord getGranularity() { * @return The start of the allocated block, or {@link WordFactory#nullPointer()} in case of an * error. */ - Pointer allocate(UnsignedWord nbytes, UnsignedWord alignment, boolean executable); + default Pointer allocate(UnsignedWord nbytes, UnsignedWord alignment, boolean executable) { + // We need this default method temporarily so that we can remove the methods allocate and + // free from all subclasses in GR-34236. + throw VMError.shouldNotReachHere("Subclasses must overwrite this method"); + } + + Pointer allocateAlignedChunk(UnsignedWord nbytes, UnsignedWord alignment); + + Pointer allocateUnalignedChunk(UnsignedWord nbytes); + + Pointer allocateExecutableMemory(UnsignedWord nbytes, UnsignedWord alignment); + + /** + * This method returns {@code true} if the memory returned by {@link #allocateUnalignedChunk} is + * guaranteed to be zeroed. + */ + boolean areUnalignedChunksZeroed(); /** * Release a block of committed memory that was allocated with {@link #allocate}, requiring the @@ -112,7 +129,20 @@ default UnsignedWord getGranularity() { * @return true on success, or false otherwise. */ @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - boolean free(PointerBase start, UnsignedWord nbytes, UnsignedWord alignment, boolean executable); + default boolean free(PointerBase start, UnsignedWord nbytes, UnsignedWord alignment, boolean executable) { + // We need this default method temporarily so that we can remove the methods allocate and + // free from all subclasses in GR-34236. + throw VMError.shouldNotReachHere("Subclasses must overwrite this method"); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + void freeAlignedChunk(PointerBase start, UnsignedWord nbytes, UnsignedWord alignment); + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + void freeUnalignedChunk(PointerBase start, UnsignedWord nbytes); + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + void freeExecutableMemory(PointerBase start, UnsignedWord nbytes, UnsignedWord alignment); /** * Called by the garbage collector before a collection is started, as an opportunity to perform diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/OSCommittedMemoryProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/OSCommittedMemoryProvider.java index 001d5f5679af..1c2e63e80773 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/OSCommittedMemoryProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/OSCommittedMemoryProvider.java @@ -101,6 +101,11 @@ public Pointer allocate(UnsignedWord size, UnsignedWord alignment, boolean execu return committed; } + @Override + public boolean areUnalignedChunksZeroed() { + return false; + } + @Override @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public boolean free(PointerBase start, UnsignedWord nbytes, UnsignedWord alignment, boolean executable) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/RuntimeReflectionConstructors.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/RuntimeReflectionConstructors.java index 70144b88b2a6..49da93a3384c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/RuntimeReflectionConstructors.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/RuntimeReflectionConstructors.java @@ -41,8 +41,8 @@ Method newMethod(Class declaringClass, byte[] parameterAnnotations, byte[] annotationDefault, byte[] typeAnnotations, - String[] parameterNames, - int[] parameterModifiers); + String[] reflectParameterNames, + int[] reflectParameterModifiers); Constructor newConstructor(Class declaringClass, Class[] parameterTypes, @@ -52,6 +52,6 @@ Constructor newConstructor(Class declaringClass, byte[] annotations, byte[] parameterAnnotations, byte[] typeAnnotations, - String[] parameterNames, - int[] parameterModifiers); + String[] reflectParameterNames, + int[] reflectParameterModifiers); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ExceptionUnwind.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ExceptionUnwind.java index 65cf964e0130..89d65429ac00 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ExceptionUnwind.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ExceptionUnwind.java @@ -68,7 +68,7 @@ public abstract class ExceptionUnwind { UNWIND_EXCEPTION_WITH_CALLEE_SAVED_REGISTERS }; - public static final FastThreadLocalObject currentException = FastThreadLocalFactory.createObject(Throwable.class); + public static final FastThreadLocalObject currentException = FastThreadLocalFactory.createObject(Throwable.class, "ExceptionUnwind.currentException"); @Uninterruptible(reason = "Called from uninterruptible callers.", mayBeInlined = true) static boolean exceptionsAreFatal() { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ImplicitExceptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ImplicitExceptions.java index 3c9c511c6984..1785e6b91cf0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ImplicitExceptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ImplicitExceptions.java @@ -53,6 +53,7 @@ public class ImplicitExceptions { public static final ClassCastException CACHED_CLASS_CAST_EXCEPTION = new ClassCastException(NO_STACK_MSG); public static final ArrayStoreException CACHED_ARRAY_STORE_EXCEPTION = new ArrayStoreException(NO_STACK_MSG); public static final IllegalArgumentException CACHED_ILLEGAL_ARGUMENT_EXCEPTION = new IllegalArgumentException(NO_STACK_MSG); + public static final NegativeArraySizeException CACHED_NEGATIVE_ARRAY_SIZE_EXCEPTION = new NegativeArraySizeException(NO_STACK_MSG); public static final ArithmeticException CACHED_ARITHMETIC_EXCEPTION = new ArithmeticException(NO_STACK_MSG); public static final AssertionError CACHED_ASSERTION_ERROR = new AssertionError(NO_STACK_MSG); @@ -63,6 +64,7 @@ public class ImplicitExceptions { public static final SubstrateForeignCallDescriptor CREATE_CLASS_CAST_EXCEPTION = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "createClassCastException", false); public static final SubstrateForeignCallDescriptor CREATE_ARRAY_STORE_EXCEPTION = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "createArrayStoreException", false); public static final SubstrateForeignCallDescriptor CREATE_ILLEGAL_ARGUMENT_EXCEPTION = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "createIllegalArgumentException", false); + public static final SubstrateForeignCallDescriptor CREATE_NEGATIVE_ARRAY_SIZE_EXCEPTION = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "createNegativeArraySizeException", false); public static final SubstrateForeignCallDescriptor CREATE_DIVISION_BY_ZERO_EXCEPTION = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "createDivisionByZeroException", false); public static final SubstrateForeignCallDescriptor CREATE_ASSERTION_ERROR_NULLARY = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "createAssertionErrorNullary", false); public static final SubstrateForeignCallDescriptor CREATE_ASSERTION_ERROR_OBJECT = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "createAssertionErrorObject", false); @@ -79,6 +81,7 @@ public class ImplicitExceptions { true); public static final SubstrateForeignCallDescriptor THROW_NEW_ILLEGAL_ARGUMENT_EXCEPTION_WITH_ARGS = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "throwNewIllegalArgumentExceptionWithArgs", true); + public static final SubstrateForeignCallDescriptor THROW_NEW_NEGATIVE_ARRAY_SIZE_EXCEPTION = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "throwNewNegativeArraySizeException", true); public static final SubstrateForeignCallDescriptor THROW_NEW_ARITHMETIC_EXCEPTION = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "throwNewArithmeticException", true); public static final SubstrateForeignCallDescriptor THROW_NEW_DIVISION_BY_ZERO_EXCEPTION = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "throwNewDivisionByZeroException", true); public static final SubstrateForeignCallDescriptor THROW_NEW_ASSERTION_ERROR_NULLARY = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "throwNewAssertionErrorNullary", true); @@ -89,6 +92,8 @@ public class ImplicitExceptions { public static final SubstrateForeignCallDescriptor GET_CACHED_CLASS_CAST_EXCEPTION = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "getCachedClassCastException", false); public static final SubstrateForeignCallDescriptor GET_CACHED_ARRAY_STORE_EXCEPTION = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "getCachedArrayStoreException", false); public static final SubstrateForeignCallDescriptor GET_CACHED_ILLEGAL_ARGUMENT_EXCEPTION = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "getCachedIllegalArgumentException", false); + public static final SubstrateForeignCallDescriptor GET_CACHED_NEGATIVE_ARRAY_SIZE_EXCEPTION = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "getCachedNegativeArraySizeException", + false); public static final SubstrateForeignCallDescriptor GET_CACHED_ARITHMETIC_EXCEPTION = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "getCachedArithmeticException", false); public static final SubstrateForeignCallDescriptor GET_CACHED_ASSERTION_ERROR = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "getCachedAssertionError", false); @@ -97,23 +102,25 @@ public class ImplicitExceptions { public static final SubstrateForeignCallDescriptor THROW_CACHED_CLASS_CAST_EXCEPTION = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "throwCachedClassCastException", true); public static final SubstrateForeignCallDescriptor THROW_CACHED_ARRAY_STORE_EXCEPTION = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "throwCachedArrayStoreException", true); public static final SubstrateForeignCallDescriptor THROW_CACHED_ILLEGAL_ARGUMENT_EXCEPTION = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "throwCachedIllegalArgumentException", true); + public static final SubstrateForeignCallDescriptor THROW_CACHED_NEGATIVE_ARRAY_SIZE_EXCEPTION = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "throwCachedNegativeArraySizeException", + true); public static final SubstrateForeignCallDescriptor THROW_CACHED_ARITHMETIC_EXCEPTION = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "throwCachedArithmeticException", true); public static final SubstrateForeignCallDescriptor THROW_CACHED_ASSERTION_ERROR = SnippetRuntime.findForeignCall(ImplicitExceptions.class, "throwCachedAssertionError", true); public static final SubstrateForeignCallDescriptor[] FOREIGN_CALLS = new SubstrateForeignCallDescriptor[]{ CREATE_NULL_POINTER_EXCEPTION, CREATE_OUT_OF_BOUNDS_EXCEPTION, CREATE_INTRINSIC_OUT_OF_BOUNDS_EXCEPTION, CREATE_CLASS_CAST_EXCEPTION, CREATE_ARRAY_STORE_EXCEPTION, - CREATE_ILLEGAL_ARGUMENT_EXCEPTION, + CREATE_ILLEGAL_ARGUMENT_EXCEPTION, CREATE_NEGATIVE_ARRAY_SIZE_EXCEPTION, CREATE_DIVISION_BY_ZERO_EXCEPTION, CREATE_ASSERTION_ERROR_NULLARY, CREATE_ASSERTION_ERROR_OBJECT, THROW_NEW_NULL_POINTER_EXCEPTION, THROW_NEW_INTRINSIC_OUT_OF_BOUNDS_EXCEPTION, THROW_NEW_CLASS_CAST_EXCEPTION, THROW_NEW_ARRAY_STORE_EXCEPTION, THROW_NEW_ARITHMETIC_EXCEPTION, THROW_NEW_OUT_OF_BOUNDS_EXCEPTION_WITH_ARGS, THROW_NEW_CLASS_CAST_EXCEPTION_WITH_ARGS, THROW_NEW_ARRAY_STORE_EXCEPTION_WITH_ARGS, THROW_NEW_ILLEGAL_ARGUMENT_EXCEPTION_WITH_ARGS, - THROW_NEW_DIVISION_BY_ZERO_EXCEPTION, THROW_NEW_ASSERTION_ERROR_NULLARY, THROW_NEW_ASSERTION_ERROR_OBJECT, + THROW_NEW_NEGATIVE_ARRAY_SIZE_EXCEPTION, THROW_NEW_DIVISION_BY_ZERO_EXCEPTION, THROW_NEW_ASSERTION_ERROR_NULLARY, THROW_NEW_ASSERTION_ERROR_OBJECT, GET_CACHED_NULL_POINTER_EXCEPTION, GET_CACHED_OUT_OF_BOUNDS_EXCEPTION, GET_CACHED_CLASS_CAST_EXCEPTION, GET_CACHED_ARRAY_STORE_EXCEPTION, GET_CACHED_ILLEGAL_ARGUMENT_EXCEPTION, - GET_CACHED_ARITHMETIC_EXCEPTION, GET_CACHED_ASSERTION_ERROR, + GET_CACHED_NEGATIVE_ARRAY_SIZE_EXCEPTION, GET_CACHED_ARITHMETIC_EXCEPTION, GET_CACHED_ASSERTION_ERROR, THROW_CACHED_NULL_POINTER_EXCEPTION, THROW_CACHED_OUT_OF_BOUNDS_EXCEPTION, THROW_CACHED_CLASS_CAST_EXCEPTION, THROW_CACHED_ARRAY_STORE_EXCEPTION, - THROW_CACHED_ILLEGAL_ARGUMENT_EXCEPTION, THROW_CACHED_ARITHMETIC_EXCEPTION, THROW_CACHED_ASSERTION_ERROR, + THROW_CACHED_ILLEGAL_ARGUMENT_EXCEPTION, THROW_CACHED_NEGATIVE_ARRAY_SIZE_EXCEPTION, THROW_CACHED_ARITHMETIC_EXCEPTION, THROW_CACHED_ASSERTION_ERROR, }; - private static final FastThreadLocalInt implicitExceptionsAreFatal = FastThreadLocalFactory.createInt(); + private static final FastThreadLocalInt implicitExceptionsAreFatal = FastThreadLocalFactory.createInt("ImplicitExceptions.implicitExceptionsAreFatal"); /** * Switch the current thread into a mode where implicit exceptions such as NullPointerException @@ -186,6 +193,13 @@ private static IllegalArgumentException createIllegalArgumentException(String me return new IllegalArgumentException(message); } + /** Foreign call: {@link #CREATE_NEGATIVE_ARRAY_SIZE_EXCEPTION}. */ + @SubstrateForeignCallTarget(stubCallingConvention = true) + private static NegativeArraySizeException createNegativeArraySizeException(int length) { + vmErrorIfImplicitExceptionsAreFatal(); + return new NegativeArraySizeException(String.valueOf(length)); + } + /** Foreign call: {@link #CREATE_DIVISION_BY_ZERO_EXCEPTION}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static ArithmeticException createDivisionByZeroException() { @@ -221,17 +235,6 @@ private static void throwNewIntrinsicOutOfBoundsException() { throw new ArrayIndexOutOfBoundsException(); } - /** Foreign call: {@link #THROW_NEW_INTRINSIC_OUT_OF_BOUNDS_EXCEPTION}. */ - @SubstrateForeignCallTarget(stubCallingConvention = true) - private static void throwNewIntrinsicOutOfBoundsExceptionWithArgs(int index, int length) { - vmErrorIfImplicitExceptionsAreFatal(); - /* - * JDK 11 added the length to the error message, we can do that for all Java versions to be - * consistent. - */ - throw new ArrayIndexOutOfBoundsException("Index " + index + " out of bounds for length " + length); - } - /** Foreign call: {@link #THROW_NEW_OUT_OF_BOUNDS_EXCEPTION_WITH_ARGS}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwNewOutOfBoundsExceptionWithArgs(int index, int length) { @@ -280,6 +283,13 @@ private static void throwNewIllegalArgumentExceptionWithArgs(String message) { throw new IllegalArgumentException(message); } + /** Foreign call: {@link #THROW_NEW_NEGATIVE_ARRAY_SIZE_EXCEPTION}. */ + @SubstrateForeignCallTarget(stubCallingConvention = true) + private static void throwNewNegativeArraySizeException(int length) { + vmErrorIfImplicitExceptionsAreFatal(); + throw new NegativeArraySizeException(String.valueOf(length)); + } + /** Foreign call: {@link #THROW_NEW_ARITHMETIC_EXCEPTION}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwNewArithmeticException() { @@ -348,6 +358,14 @@ private static IllegalArgumentException getCachedIllegalArgumentException() { return CACHED_ILLEGAL_ARGUMENT_EXCEPTION; } + /** Foreign call: {@link #GET_CACHED_NEGATIVE_ARRAY_SIZE_EXCEPTION}. */ + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") + @SubstrateForeignCallTarget(stubCallingConvention = true) + private static NegativeArraySizeException getCachedNegativeArraySizeException() { + vmErrorIfImplicitExceptionsAreFatal(); + return CACHED_NEGATIVE_ARRAY_SIZE_EXCEPTION; + } + /** Foreign call: {@link #GET_CACHED_ARITHMETIC_EXCEPTION}. */ @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) @@ -404,6 +422,14 @@ private static void throwCachedIllegalArgumentException() { throw CACHED_ILLEGAL_ARGUMENT_EXCEPTION; } + /** Foreign call: {@link #THROW_CACHED_NEGATIVE_ARRAY_SIZE_EXCEPTION}. */ + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") + @SubstrateForeignCallTarget(stubCallingConvention = true) + private static void throwCachedNegativeArraySizeException() { + vmErrorIfImplicitExceptionsAreFatal(); + throw CACHED_NEGATIVE_ARRAY_SIZE_EXCEPTION; + } + /** Foreign call: {@link #THROW_CACHED_ARITHMETIC_EXCEPTION}. */ @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/JavaFrameAnchors.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/JavaFrameAnchors.java index cbc86c4908f0..1156f3bdea51 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/JavaFrameAnchors.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/JavaFrameAnchors.java @@ -36,7 +36,7 @@ */ public class JavaFrameAnchors { - private static final FastThreadLocalWord lastAnchor = FastThreadLocalFactory.createWord().setMaxOffset(FastThreadLocal.BYTE_OFFSET); + private static final FastThreadLocalWord lastAnchor = FastThreadLocalFactory.createWord("JavaFrameAnchors.lastAnchor").setMaxOffset(FastThreadLocal.BYTE_OFFSET); public static void pushFrameAnchor(JavaFrameAnchor anchor) { anchor.setPreviousAnchor(lastAnchor.get()); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/SubstrateStackIntrospection.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/SubstrateStackIntrospection.java index 6819ad7e7bfb..d015dffd0b99 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/SubstrateStackIntrospection.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/SubstrateStackIntrospection.java @@ -362,10 +362,6 @@ public String toString() { JavaConstant con = getLocalConstant(i); if (con.getJavaKind() != JavaKind.Illegal) { result.append("\n local ").append(i); - String name = frameInfo.getLocalVariableName(i); - if (name != null) { - result.append(" ").append(name); - } if (con.getJavaKind() == JavaKind.Object) { if (isVirtual(i)) { result.append(" [virtual object]"); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/ThreadStackPrinter.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/ThreadStackPrinter.java index 338e13d45439..339c434efe67 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/ThreadStackPrinter.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/ThreadStackPrinter.java @@ -104,6 +104,7 @@ public void decodeConstant(ValueInfo valueInfo, NonmovableObjectArray frameIn private static SingleShotFrameInfoQueryResultAllocator SingleShotFrameInfoQueryResultAllocator = new SingleShotFrameInfoQueryResultAllocator(); private static DummyValueInfoAllocator DummyValueInfoAllocator = new DummyValueInfoAllocator(); + private static CodeInfoAccess.FrameInfoState frameInfoState = new CodeInfoAccess.FrameInfoState(); @Override protected void logFrame(Log log, Pointer sp, CodePointer ip, CodeInfo codeInfo, DeoptimizedFrame deoptFrame) { @@ -111,12 +112,13 @@ protected void logFrame(Log log, Pointer sp, CodePointer ip, CodeInfo codeInfo, logVirtualFrames(log, sp, ip, deoptFrame); } else { frameInfoReader.reset(); - long entryOffset = CodeInfoAccess.initFrameInfoReader(codeInfo, ip, frameInfoReader); - if (entryOffset >= 0) { + frameInfoState.reset(); + CodeInfoAccess.initFrameInfoReader(codeInfo, ip, frameInfoReader, frameInfoState); + if (frameInfoState.entryOffset >= 0) { boolean isFirst = true; FrameInfoQueryResult validResult; SingleShotFrameInfoQueryResultAllocator.reload(); - while ((validResult = CodeInfoAccess.nextFrameInfo(codeInfo, entryOffset, frameInfoReader, SingleShotFrameInfoQueryResultAllocator, DummyValueInfoAllocator, isFirst)) != null) { + while ((validResult = CodeInfoAccess.nextFrameInfo(codeInfo, frameInfoReader, SingleShotFrameInfoQueryResultAllocator, DummyValueInfoAllocator, frameInfoState)) != null) { SingleShotFrameInfoQueryResultAllocator.reload(); if (!isFirst) { log.newline(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java index 76d3e06361c3..3f1d64c426a0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java @@ -56,7 +56,6 @@ import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.NeverInline; -import com.oracle.svm.core.annotate.RestrictHeapAccess; import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.ReferenceHandler; @@ -86,7 +85,7 @@ public static JavaThreads singleton() { } /** The {@link java.lang.Thread} for the {@link IsolateThread}. */ - static final FastThreadLocalObject currentThread = FastThreadLocalFactory.createObject(Thread.class).setMaxOffset(FastThreadLocal.BYTE_OFFSET); + static final FastThreadLocalObject currentThread = FastThreadLocalFactory.createObject(Thread.class, "JavaThreads.currentThread").setMaxOffset(FastThreadLocal.BYTE_OFFSET); /** * The number of running non-daemon threads. The initial value accounts for the main thread, @@ -177,16 +176,18 @@ public static void setThreadStatus(Thread thread, int threadStatus) { * in VM-internal contexts. */ public static boolean isInterrupted(Thread thread) { - if (JavaVersionUtil.JAVA_SPEC >= 14) { - return toTarget(thread).interruptedJDK14OrLater; + if (JavaVersionUtil.JAVA_SPEC >= 17) { + return toTarget(thread).interruptedJDK17OrLater; } - return toTarget(thread).interrupted; + return toTarget(thread).interruptedJDK11OrEarlier; } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) protected static AtomicReference getUnsafeParkEvent(Thread thread) { return toTarget(thread).unsafeParkEvent; } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) protected static AtomicReference getSleepParkEvent(Thread thread) { return toTarget(thread).sleepParkEvent; } @@ -415,18 +416,9 @@ public boolean tearDown() { return tearDownJavaThreads(); } - /** - * Detach the provided Java thread. - * - * When this method is being executed, we expect that the current thread owns - * {@linkplain VMThreads#THREAD_MUTEX}. This is fine even though this method is not - * {@linkplain Uninterruptible} because this method is either executed as part of a VM operation - * or {@linkplain StatusSupport#setStatusIgnoreSafepoints()} was called. - */ - @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while detaching a thread.") + @Uninterruptible(reason = "Thread is detaching and holds the THREAD_MUTEX.") public static void detachThread(IsolateThread vmThread) { - VMThreads.THREAD_MUTEX.assertIsOwner("Must hold the VMThreads mutex"); - assert StatusSupport.isStatusIgnoreSafepoints(vmThread) || VMOperation.isInProgress(); + VMThreads.THREAD_MUTEX.assertIsOwner("Must hold the THREAD_MUTEX."); Thread thread = currentThread.get(vmThread); ParkEvent.detach(getUnsafeParkEvent(thread)); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/ParkEvent.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/ParkEvent.java index 8e8088306f67..24ddca3b3b97 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/ParkEvent.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/ParkEvent.java @@ -24,8 +24,10 @@ */ package com.oracle.svm.core.thread; +import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.nativeimage.ImageSingletons; +import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.jdk.UninterruptibleUtils.AtomicReference; import com.oracle.svm.core.util.VMError; @@ -80,6 +82,7 @@ protected ParkEvent() { protected abstract void unpark(); /** Use up the cons-cell for this ParkEvent. */ + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) ParkEventConsCell consumeConsCell() { assert consCell != null : "Consuming null cons cell."; ParkEventConsCell result = consCell; @@ -129,6 +132,7 @@ private static ParkEvent acquire() { return result; } + @Uninterruptible(reason = "Thread is detaching and holds the THREAD_MUTEX.") static void detach(AtomicReference ref) { /* * We must not reset the AtomicReference back to null, because a racing thread could @@ -141,6 +145,7 @@ static void detach(AtomicReference ref) { } } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) private static void release(ParkEvent event) { ParkEventList.getSingleton().push(event); } @@ -190,6 +195,7 @@ final class ParkEventList { private static final ParkEventList SINGLETON = new ParkEventList(); + @Fold public static ParkEventList getSingleton() { return SINGLETON; } @@ -203,6 +209,7 @@ private ParkEventList() { } /** Push an element on to the free-list. */ + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) protected void push(ParkEvent element) { ParkEventConsCell sampleHead; /* Use up the cons-cell for each attempted push to avoid the ABA problem on pops. */ @@ -250,6 +257,7 @@ protected ParkEventConsCell getNext() { return next; } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) protected void setNext(ParkEventConsCell next) { this.next = next; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Safepoint.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Safepoint.java index 5d6be7983115..d0f832bea9ed 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Safepoint.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Safepoint.java @@ -26,6 +26,7 @@ import java.util.concurrent.atomic.AtomicInteger; +import com.oracle.svm.core.thread.VMThreads.SafepointBehavior; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.graph.Node.ConstantNodeParameter; @@ -329,7 +330,7 @@ private static void notInlinedLockNoTransition() { * value. * */ - static final FastThreadLocalInt safepointRequested = FastThreadLocalFactory.createInt().setMaxOffset(FastThreadLocal.FIRST_CACHE_LINE); + static final FastThreadLocalInt safepointRequested = FastThreadLocalFactory.createInt("Safepoint.safepointRequested").setMaxOffset(FastThreadLocal.FIRST_CACHE_LINE); /** The value to reset a thread's {@link #safepointRequested} value to after a safepoint. */ static final int THREAD_REQUEST_RESET = Integer.MAX_VALUE; @@ -386,8 +387,8 @@ private static void enterSlowPathSafepointCheck() throws Throwable { @AlwaysInline("Always inline into foreign call stub") @Uninterruptible(reason = "Must not contain safepoint checks") public static void slowPathSafepointCheck() throws Throwable { - if (StatusSupport.isStatusIgnoreSafepoints(CurrentIsolate.getCurrentThread())) { - /* The thread is detaching so it won't ever need to execute a safepoint again. */ + if (SafepointBehavior.ignoresSafepoints()) { + /* Safepoints are explicitly disabled for this thread. */ Safepoint.setSafepointRequested(THREAD_REQUEST_RESET); return; } @@ -518,8 +519,8 @@ public static void transitionVMToNative() { @Uninterruptible(reason = "Must not contain safepoint checks") private static void enterSlowPathTransitionFromNativeToNewStatus(int newStatus) { VMError.guarantee(StatusSupport.isStatusNativeOrSafepoint(), "Must either be at a safepoint or in native mode"); - VMError.guarantee(!StatusSupport.isStatusIgnoreSafepoints(CurrentIsolate.getCurrentThread()), - "When safepoints are disabled, the thread can only be in Native mode, so the fast path transition must succeed and this slow path must not be called"); + VMError.guarantee(!SafepointBehavior.ignoresSafepoints(), + "The safepoint handling doesn't change the status of threads that ignore safepoints. So, the fast path transition must succeed and this slow path must not be called"); Statistics.incSlowPathFrozen(); try { @@ -634,16 +635,12 @@ private static void requestSafepoints(String reason) { final Log trace = Log.noopLog().string("[Safepoint.Master.requestSafepoints: reason: ").string(reason); // Walk the threads list and ask each thread (except myself) to come to a safepoint. - // TODO: Do I always bring *all* threads to a safepoint? Could I stop some of them? for (IsolateThread vmThread = VMThreads.firstThread(); vmThread.isNonNull(); vmThread = VMThreads.nextThread(vmThread)) { if (isMyself(vmThread)) { continue; } - if (StatusSupport.isStatusIgnoreSafepoints(vmThread)) { - /* - * If the thread is exiting/exited or safepoints are disabled for another - * reason, do not ask it to stop at safepoints. - */ + if (SafepointBehavior.ignoresSafepoints(vmThread)) { + /* If safepoints are disabled, do not ask it to stop at safepoints. */ continue; } requestSafepoint(vmThread); @@ -701,32 +698,47 @@ private static void restoreSafepointRequestedValue(IsolateThread vmThread) { /** Wait for there to be no threads (except myself) still waiting to reach a safepoint. */ private static void waitForSafepoints(String reason) { - final Log trace = Log.noopLog().string("[Safepoint.Master.waitForSafepoints: reason: ").string(reason).newline(); VMThreads.THREAD_MUTEX.assertIsOwner("Must hold mutex while waiting for safepoints."); final long startNanos = System.nanoTime(); long loopNanos = startNanos; + long warningNanos = -1; + long failureNanos = -1; + for (int loopCount = 1; /* return */; loopCount += 1) { int atSafepoint = 0; int ignoreSafepoints = 0; int notAtSafepoint = 0; + int lostUpdates = 0; for (IsolateThread vmThread = VMThreads.firstThread(); vmThread.isNonNull(); vmThread = VMThreads.nextThread(vmThread)) { if (isMyself(vmThread)) { /* Don't wait for myself. */ - } else if (StatusSupport.isStatusIgnoreSafepoints(vmThread)) { - /* - * If the thread has exited or safepoints are disabled for another reason, - * then I do not need to worry about bringing it to a safepoint. - */ - ignoreSafepoints += 1; + continue; + } + + /*- + * The status must be read before the safepoint behavior to prevent races + * like the following: + * - thread A reads the safepoint behavior of thread B. + * - thread B sets the safepoint behavior to PREVENT_VM_FROM_REACHING_SAFEPOINT. + * - thread B sets the status to STATUS_IN_NATIVE. + * - thread A reads the status of thread B and the VM reaches a safepoint. + */ + int status = StatusSupport.getStatusVolatile(vmThread); + int safepointBehavior = SafepointBehavior.getSafepointBehaviorVolatile(vmThread); + if (safepointBehavior == SafepointBehavior.PREVENT_VM_FROM_REACHING_SAFEPOINT) { + notAtSafepoint++; + } else if (safepointBehavior == SafepointBehavior.THREAD_CRASHED) { + ignoreSafepoints++; } else { - int status = StatusSupport.getStatusVolatile(vmThread); + assert safepointBehavior == SafepointBehavior.ALLOW_SAFEPOINT; switch (status) { case StatusSupport.STATUS_IN_JAVA: case StatusSupport.STATUS_IN_VM: { /* Re-request the safepoint in case of a lost update. */ - if (getSafepointRequested(vmThread) > 0 && !StatusSupport.isStatusIgnoreSafepoints(vmThread)) { + if (getSafepointRequested(vmThread) > 0) { requestSafepoint(vmThread); + lostUpdates++; } notAtSafepoint += 1; break; @@ -758,24 +770,48 @@ private static void waitForSafepoints(String reason) { } } if (notAtSafepoint == 0) { - trace.string(" returns"); - if (trace.isEnabled() && Statistics.Options.GatherSafepointStatistics.getValue()) { - trace.string(" with installed: ").signed(Statistics.getInstalled()); - } - trace.string("]").newline(); return; } - trace.string(" loopCount: ").signed(loopCount) - .string(" atSafepoint: ").signed(atSafepoint) - .string(" ignoreSafepoints: ").signed(ignoreSafepoints) - .string(" notAtSafepoint: ").signed(notAtSafepoint) - .newline(); - loopNanos = doNotLoopTooLong(loopNanos, startNanos, reason); - maybeFatallyTooLong(startNanos, reason); + if (warningNanos == -1 || failureNanos == -1) { + warningNanos = Safepoint.getSafepointPromptnessWarningNanos(); + failureNanos = Safepoint.getSafepointPromptnessFailureNanos(); + } + + long nanosSinceStart = TimeUtils.nanoSecondsSince(startNanos); + if (warningNanos > 0 || failureNanos > 0) { + long nanosSinceLastWarning = TimeUtils.nanoSecondsSince(loopNanos); + + boolean printWarning = warningNanos > 0 && TimeUtils.nanoTimeLessThan(warningNanos, nanosSinceLastWarning); + boolean fatalError = failureNanos > 0 && TimeUtils.nanoTimeLessThan(failureNanos, nanosSinceStart); + if (printWarning || fatalError) { + Log.log().string("[Safepoint.Master: not all threads reached a safepoint (").string(reason).string(") within ").signed(warningNanos).string(" ns. Total wait time so far: ") + .signed(nanosSinceStart).string(" ns.").newline(); + Log.log().string(" loopCount: ").signed(loopCount) + .string(" atSafepoint: ").signed(atSafepoint) + .string(" ignoreSafepoints: ").signed(ignoreSafepoints) + .string(" notAtSafepoint: ").signed(notAtSafepoint) + .string(" lostUpdates: ").signed(lostUpdates) + .string("]") + .newline(); + + loopNanos = System.nanoTime(); + if (fatalError) { + VMError.guarantee(false, "Safepoint promptness failure."); + } + } + } - // Wait impatiently for requested threads to come to a safepoint. - PauseNode.pause(); + // Wait for requested threads to come to a safepoint. + if (VMThreads.singleton().supportsPatientSafepoints()) { + if (nanosSinceStart < TimeUtils.nanosPerMilli) { + VMThreads.singleton().yield(); + } else { + VMThreads.singleton().nativeSleep(1); + } + } else { + PauseNode.pause(); + } } } @@ -785,7 +821,7 @@ private static void releaseSafepoints(String reason) { VMThreads.THREAD_MUTEX.assertIsOwner("Must hold mutex when releasing safepoints."); // Set all the thread statuses that are at safepoint back to being in native code. for (IsolateThread vmThread = VMThreads.firstThread(); vmThread.isNonNull(); vmThread = VMThreads.nextThread(vmThread)) { - if (!isMyself(vmThread) && !StatusSupport.isStatusIgnoreSafepoints(vmThread)) { + if (!isMyself(vmThread) && !SafepointBehavior.ignoresSafepoints(vmThread)) { if (trace.isEnabled()) { trace.string(" vmThread status: ").string(StatusSupport.getStatusString(vmThread)); } @@ -808,37 +844,6 @@ private static void releaseSafepoints(String reason) { trace.string("]").newline(); } - /** Have I looped for too long? If so, complain, but reset the wait. */ - private static long doNotLoopTooLong(long loopNanos, long startNanos, String reason) { - long result = loopNanos; - final long waitedNanos = TimeUtils.nanoSecondsSince(loopNanos); - final long warningNanos = Safepoint.getSafepointPromptnessWarningNanos(); - if ((0 < warningNanos) && TimeUtils.nanoTimeLessThan(warningNanos, waitedNanos)) { - final Log warning = Log.log().string("[Safepoint.Master.doNotLoopTooLong:"); - warning.string(" warningNanos: ").signed(warningNanos).string(" < ").string(" waitedNanos: ").signed(waitedNanos); - warning.string(" startNanos: ").signed(startNanos); - warning.string(" reason: ").string(reason).string("]").newline(); - result = System.nanoTime(); - } - return result; - } - - private static void maybeFatallyTooLong(long startNanos, String reason) { - final long failureNanos = Safepoint.getSafepointPromptnessFailureNanos(); - if (0 < failureNanos) { - /* If a promptness limit was set. */ - final long nanosSinceStart = TimeUtils.nanoSecondsSince(startNanos); - if (TimeUtils.nanoTimeLessThan(failureNanos, nanosSinceStart)) { - /* If the promptness limit was exceeded. */ - final Log warning = Log.log().string("[Safepoint.Master.maybeFatallyTooLong:"); - warning.string(" failureNanos: ").signed(failureNanos).string(" < nanosSinceStart: ").signed(nanosSinceStart); - warning.string(" startNanos: ").signed(startNanos); - warning.string(" reason: ").string(reason).string("]").newline(); - VMError.guarantee(false, "Safepoint promptness failure."); - } - } - } - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) protected IsolateThread getRequestingThread() { return requestingThread; @@ -864,11 +869,15 @@ public static int countingVMOperation() { int notAtSafepoint = 0; for (IsolateThread vmThread = VMThreads.firstThread(); vmThread.isNonNull(); vmThread = VMThreads.nextThread(vmThread)) { - if (StatusSupport.isStatusIgnoreSafepoints(vmThread)) { + int safepointBehavior = SafepointBehavior.getSafepointBehaviorVolatile(vmThread); + int status = StatusSupport.getStatusVolatile(vmThread); + if (safepointBehavior == SafepointBehavior.PREVENT_VM_FROM_REACHING_SAFEPOINT) { + notAtSafepoint++; + } else if (safepointBehavior == SafepointBehavior.THREAD_CRASHED) { ignoreSafepoints += 1; } else { + assert safepointBehavior == SafepointBehavior.ALLOW_SAFEPOINT; // Check if the thread is at a safepoint or in native code. - int status = StatusSupport.getStatusVolatile(vmThread); switch (status) { case StatusSupport.STATUS_IN_SAFEPOINT: atSafepoint += 1; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java index 5f45e94a4b90..8f3c109bdff4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java @@ -43,7 +43,7 @@ import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.jdk.JDK11OrEarlier; import com.oracle.svm.core.jdk.JDK11OrLater; -import com.oracle.svm.core.jdk.JDK14OrLater; +import com.oracle.svm.core.jdk.JDK17OrLater; import com.oracle.svm.core.jdk.JDK8OrEarlier; import com.oracle.svm.core.jdk.LoomJDK; import com.oracle.svm.core.jdk.NotLoomJDK; @@ -64,17 +64,17 @@ public final class Target_java_lang_Thread { * * After JDK 11, a field with same name has been introduced and the logic to set / reset it has * moved into Java code. So this injected field and the substitutions that maintain it are no - * longer necessary. See {@link #interruptedJDK14OrLater}. + * longer necessary. See {@link #interruptedJDK17OrLater}. */ @Inject // @TargetElement(onlyWith = JDK11OrEarlier.class) // @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) // - volatile boolean interrupted; + volatile boolean interruptedJDK11OrEarlier; @Alias // - @TargetElement(name = "interrupted", onlyWith = JDK14OrLater.class) // + @TargetElement(name = "interrupted", onlyWith = JDK17OrLater.class) // @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) // - volatile boolean interruptedJDK14OrLater; + volatile boolean interruptedJDK17OrLater; @Inject @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset)// boolean wasStartedByCurrentIsolate; @@ -379,7 +379,7 @@ private void setPriority0(int priority) { @Substitute @TargetElement(onlyWith = JDK11OrEarlier.class) private boolean isInterrupted(boolean clearInterrupted) { - final boolean result = interrupted; + final boolean result = interruptedJDK11OrEarlier; if (result && clearInterrupted) { /* * As we don't use a lock, it is possible to observe any kinds of races with other @@ -389,7 +389,7 @@ private boolean isInterrupted(boolean clearInterrupted) { * isInterrupted as clearInterrupted may only be true if this method is being executed * by the current thread. */ - interrupted = false; + interruptedJDK11OrEarlier = false; } return result; } @@ -403,7 +403,7 @@ private boolean isInterrupted(boolean clearInterrupted) { @Substitute void interrupt0() { if (JavaVersionUtil.JAVA_SPEC <= 11) { - interrupted = true; + interruptedJDK11OrEarlier = true; } else { /* * After JDK 11, the interrupted flag is maintained by the JDK in Java code, i.e., @@ -537,7 +537,7 @@ private static Map getAllStackTraces() { } @Substitute - @TargetElement(onlyWith = JDK14OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) private static void clearInterruptEvent() { /* * In the JDK, this is a no-op except on Windows. The JDK resets the interrupt event used by diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/ThreadingSupportImpl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/ThreadingSupportImpl.java index 990d9b3db3bb..d250d33229f8 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/ThreadingSupportImpl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/ThreadingSupportImpl.java @@ -233,9 +233,9 @@ private void invokeCallback() { } } - private static final FastThreadLocalObject activeTimer = FastThreadLocalFactory.createObject(RecurringCallbackTimer.class); + private static final FastThreadLocalObject activeTimer = FastThreadLocalFactory.createObject(RecurringCallbackTimer.class, "ThreadingSupportImpl.activeTimer"); - private static final FastThreadLocalInt currentPauseDepth = FastThreadLocalFactory.createInt(); + private static final FastThreadLocalInt currentPauseDepth = FastThreadLocalFactory.createInt("ThreadingSupportImpl.currentPauseDepth"); private static final String enableSupportOption = SubstrateOptionsParser.commandArgument(SupportRecurringCallback, "+"); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java index c1b7e49f5701..8047f6dbf0bc 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java @@ -30,6 +30,7 @@ import java.util.Collections; import java.util.List; +import com.oracle.svm.core.thread.VMThreads.SafepointBehavior; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.CurrentIsolate; @@ -261,6 +262,7 @@ void enqueueFromNonJavaThread(NativeVMOperationData data) { private void enqueue(VMOperation operation, NativeVMOperationData data) { StackOverflowCheck.singleton().makeYellowZoneAvailable(); try { + VMError.guarantee(!SafepointBehavior.ignoresSafepoints(), "could cause deadlocks otherwise"); log().string("[VMOperationControl.enqueue:").string(" operation: ").string(operation.getName()); if (!MultiThreaded.getValue()) { // no safepoint is needed, so we can always directly execute the operation diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java index 25d7d2c58f7c..53bb09969504 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java @@ -26,6 +26,9 @@ import static com.oracle.svm.core.SubstrateOptions.UseDedicatedVMOperationThread; +import com.oracle.svm.core.annotate.NeverInline; +import com.oracle.svm.core.nodes.CFunctionEpilogueNode; +import com.oracle.svm.core.nodes.CFunctionPrologueNode; import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.replacements.ReplacementsUtil; @@ -44,8 +47,6 @@ import org.graalvm.word.WordFactory; import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.annotate.NeverInline; -import com.oracle.svm.core.annotate.RestrictHeapAccess; import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.c.function.CEntryPointErrors; import com.oracle.svm.core.c.function.CFunctionOptions; @@ -84,10 +85,9 @@ public static VMThreads singleton() { * the mutexes are acquired (VMOperation queue mutex first, {@link #THREAD_MUTEX} second). If * the VM operation causes a safepoint, then it is possible that the {@link #THREAD_MUTEX} was * already acquired for safepoint reasons. - *

  • Acquire the mutex outside of a VM operation but only execute uninterruptible code. This - * is safe as the uninterruptible code cannot trigger a safepoint.
  • - *
  • Acquire the mutex from a thread that previously called - * {@link StatusSupport#setStatusIgnoreSafepoints()}.
  • + *
  • Acquire the mutex from a thread that is either not yet attached + * {@link StatusSupport#STATUS_CREATED} or currently in native code + * ({@link StatusSupport#STATUS_IN_NATIVE}).
  • * * * Deadlock example 1: @@ -138,17 +138,17 @@ public static VMThreads singleton() { * The next element in the linked list of {@link IsolateThread}s. A thread points to itself with * this field after being removed from the linked list. */ - public static final FastThreadLocalWord nextTL = FastThreadLocalFactory.createWord(); - private static final FastThreadLocalWord OSThreadIdTL = FastThreadLocalFactory.createWord(); - protected static final FastThreadLocalWord OSThreadHandleTL = FastThreadLocalFactory.createWord(); - public static final FastThreadLocalWord IsolateTL = FastThreadLocalFactory.createWord(); + public static final FastThreadLocalWord nextTL = FastThreadLocalFactory.createWord("VMThreads.nextTL"); + private static final FastThreadLocalWord OSThreadIdTL = FastThreadLocalFactory.createWord("VMThreads.OSThreadIdTL"); + protected static final FastThreadLocalWord OSThreadHandleTL = FastThreadLocalFactory.createWord("VMThreads.OSThreadHandleTL"); + public static final FastThreadLocalWord IsolateTL = FastThreadLocalFactory.createWord("VMThreads.IsolateTL"); /** The highest stack address. */ - public static final FastThreadLocalWord StackBase = FastThreadLocalFactory.createWord(); + public static final FastThreadLocalWord StackBase = FastThreadLocalFactory.createWord("VMThreads.StackBase"); /** * The lowest stack address. Note that this value does not necessarily match the value that is * used for the stack overflow check. */ - public static final FastThreadLocalWord StackEnd = FastThreadLocalFactory.createWord(); + public static final FastThreadLocalWord StackEnd = FastThreadLocalFactory.createWord("VMThreads.StackEnd"); private static final int STATE_UNINITIALIZED = 1; private static final int STATE_INITIALIZING = 2; @@ -206,7 +206,7 @@ public static boolean ensureInitialized() { * Stores the unaligned memory address returned by calloc, so that we can properly free the * memory again. */ - private static final FastThreadLocalWord unalignedIsolateThreadMemoryTL = FastThreadLocalFactory.createWord(); + private static final FastThreadLocalWord unalignedIsolateThreadMemoryTL = FastThreadLocalFactory.createWord("VMThreads.unalignedIsolateThreadMemoryTL"); /** * Allocate native memory for a {@link IsolateThread}. The returned memory must be initialized @@ -329,7 +329,10 @@ public void detachThread(IsolateThread thread) { cleanupBeforeDetach(thread); - setStatusIgnoreSafepointsAndLock(); + // From this point on, all code must be fully uninterruptible because this thread either + // holds the THREAD_MUTEX (see the JavaDoc on THREAD_MUTEX) or because the IsolateThread was + // already freed. + lockVMMutexInNativeCode(); OSThreadHandle threadToCleanup; try { detachThreadInSafeContext(thread); @@ -355,25 +358,21 @@ public void detachThread(IsolateThread thread) { cleanupExitedOsThread(threadToCleanup); } - /* - * Make me immune to safepoints (the safepoint mechanism ignores me). We are calling functions - * that are not marked as @Uninterruptible during the detach process. We hold the THREAD_MUTEX, - * so we know that we are not going to be interrupted by a safepoint. But a safepoint can - * already be requested, or our safepoint counter can reach 0 - so it is still possible that we - * enter the safepoint slow path. - * - * Between setting the status and acquiring the TREAD_MUTEX, we must not access the heap. - * Otherwise, we risk a race with the GC as this thread will continue executing even though the - * VM is at a safepoint. - */ @Uninterruptible(reason = "Called from uninterruptible code.") - @NeverInline("Prevent that anything floats between setting the status and acquiring the mutex.") - private static void setStatusIgnoreSafepointsAndLock() { - StatusSupport.setStatusIgnoreSafepoints(); - THREAD_MUTEX.lockNoTransition(); + @NeverInline("Must not be inlined in a caller that has an exception handler: We only support InvokeNode and not InvokeWithExceptionNode between a CFunctionPrologueNode and CFunctionEpilogueNode.") + private static void lockVMMutexInNativeCode() { + CFunctionPrologueNode.cFunctionPrologue(StatusSupport.STATUS_IN_NATIVE); + lockVMMutexInNativeCode0(); + CFunctionEpilogueNode.cFunctionEpilogue(StatusSupport.STATUS_IN_NATIVE); } - @Uninterruptible(reason = "Isolate thread will be freed.", calleeMustBe = false) + @Uninterruptible(reason = "Must not stop while in native.") + @NeverInline("Provide a return address for the Java frame anchor.") + private static void lockVMMutexInNativeCode0() { + VMThreads.THREAD_MUTEX.lockNoTransition(); + } + + @Uninterruptible(reason = "Thread is detaching and holds the THREAD_MUTEX.") private static void releaseThread(IsolateThread thread) { THREAD_MUTEX.guaranteeIsOwner("This mutex must be locked to prevent that a GC is triggered while detaching a thread from the heap"); Heap.getHeap().detachThread(thread); @@ -399,15 +398,15 @@ private void cleanupExitedOsThread(OSThreadHandle threadToCleanup) { } } - @Uninterruptible(reason = "Manipulates the threads list; broadcasts on changes.") + @Uninterruptible(reason = "Thread is detaching and holds the THREAD_MUTEX.") private static void detachThreadInSafeContext(IsolateThread thread) { - detachJavaThread(thread); + JavaThreads.detachThread(thread); removeFromThreadList(thread); // Signal that the VMThreads list has changed. THREAD_LIST_CONDITION.broadcast(); } - @Uninterruptible(reason = "Called from uninterruptible code.") + @Uninterruptible(reason = "Thread is detaching and holds the THREAD_MUTEX.") private static void removeFromThreadList(IsolateThread thread) { IsolateThread previous = WordFactory.nullPointer(); IsolateThread current = head; @@ -449,13 +448,7 @@ private void waitUntilLastOsThreadExited() { cleanupExitedOsThreads(); } - @Uninterruptible(reason = "For calling interruptible code from uninterruptible code.", calleeMustBe = false) - private static void detachJavaThread(IsolateThread thread) { - JavaThreads.detachThread(thread); - } - @Uninterruptible(reason = "Called from uninterruptible code, but still safe at this point.", calleeMustBe = false, mayBeInlined = true) - @RestrictHeapAccess(access = RestrictHeapAccess.Access.UNRESTRICTED, overridesCallers = true, reason = "Still safe at this point.") private static void cleanupBeforeDetach(IsolateThread thread) { JavaThreads.cleanupBeforeDetach(thread); } @@ -524,6 +517,16 @@ public void nativeSleep(@SuppressWarnings("unused") int milliseconds) { throw VMError.shouldNotReachHere(); } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public void yield() { + throw VMError.shouldNotReachHere(); + } + + // Should not be implemented and will be removed with GR-34388. + public boolean supportsPatientSafepoints() { + return false; + } + @Uninterruptible(reason = "Called from uninterruptible verification code.", mayBeInlined = true) public boolean verifyThreadIsAttached(IsolateThread thread) { return nextThread(thread) != thread; @@ -611,16 +614,7 @@ public static boolean printLocationInfo(Log log, UnsignedWord value, boolean all public static class StatusSupport { /** The status of a {@link IsolateThread}. */ - public static final FastThreadLocalInt statusTL = FastThreadLocalFactory.createInt().setMaxOffset(FastThreadLocal.FIRST_CACHE_LINE); - - /** - * Boolean flag whether safepoints are disabled. This is a separate thread local in addition - * to the {@link #statusTL} because we need the disabled flag to be "sticky": once - * safepoints are disabled, they must never be enabled again. Either the thread is getting - * detached, or a fatal error occurred and we are printing diagnostics before killing the - * VM. - */ - private static final FastThreadLocalInt safepointsDisabledTL = FastThreadLocalFactory.createInt(); + public static final FastThreadLocalInt statusTL = FastThreadLocalFactory.createInt("StatusSupport.statusTL").setMaxOffset(FastThreadLocal.FIRST_CACHE_LINE); /** An illegal thread state for places where we need to pass a value. */ public static final int STATUS_ILLEGAL = -1; @@ -640,18 +634,18 @@ public static class StatusSupport { private static final int MAX_STATUS = STATUS_IN_VM; @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - private static String statusToString(int status, boolean safepointsDisabled) { + private static String statusToString(int status) { switch (status) { case STATUS_CREATED: - return safepointsDisabled ? "STATUS_CREATED (safepoints disabled)" : "STATUS_CREATED"; + return "STATUS_CREATED"; case STATUS_IN_JAVA: - return safepointsDisabled ? "STATUS_IN_JAVA (safepoints disabled)" : "STATUS_IN_JAVA"; + return "STATUS_IN_JAVA"; case STATUS_IN_SAFEPOINT: - return safepointsDisabled ? "STATUS_IN_SAFEPOINT (safepoints disabled)" : "STATUS_IN_SAFEPOINT"; + return "STATUS_IN_SAFEPOINT"; case STATUS_IN_NATIVE: - return safepointsDisabled ? "STATUS_IN_NATIVE (safepoints disabled)" : "STATUS_IN_NATIVE"; + return "STATUS_IN_NATIVE"; case STATUS_IN_VM: - return safepointsDisabled ? "STATUS_IN_VM (safepoints disabled)" : "STATUS_IN_VM"; + return "STATUS_IN_VM"; default: return "STATUS error"; } @@ -662,7 +656,7 @@ private static String statusToString(int status, boolean safepointsDisabled) { /** For debugging. */ @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static String getStatusString(IsolateThread vmThread) { - return statusToString(statusTL.getVolatile(vmThread), isStatusIgnoreSafepoints(vmThread)); + return statusToString(statusTL.getVolatile(vmThread)); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @@ -741,16 +735,6 @@ public static boolean isStatusJava() { return (statusTL.getVolatile() == STATUS_IN_JAVA); } - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public static boolean isStatusIgnoreSafepoints() { - return safepointsDisabledTL.getVolatile() == 1; - } - - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public static boolean isStatusIgnoreSafepoints(IsolateThread vmThread) { - return safepointsDisabledTL.getVolatile(vmThread) == 1; - } - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static void assertStatusJava() { String msg = "Thread status must be 'Java'."; @@ -787,20 +771,10 @@ public static void assertStatusVM() { } } - /** - * Make myself immune to safepoints. Set the thread status to ensure that the safepoint - * mechanism ignores me. It is not necessary to clear a pending safepoint request (i.e., to - * reset the safepoint counter) because the safepoint slow path is going to do that in case. - * - * Be careful with this method. If a thread is marked to ignore safepoints, it means that it - * can continue executing while a safepoint (and therefore a GC) is in progress. So, either - * prevent that a safepoint can be initiated (by holding the {@link #THREAD_MUTEX}) or make - * sure that this thread does not access any movable heap objects (even executing write - * barriers can already cause issues). - */ + // This method will be removed in GR-34435. @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static void setStatusIgnoreSafepoints() { - safepointsDisabledTL.setVolatile(1); + SafepointBehavior.markThreadAsCrashed(); } public static boolean isValidStatus(int status) { @@ -828,13 +802,97 @@ public static int getNewThreadStatus(CFunctionOptions.Transition transition) { } } + public static class SafepointBehavior { + /** Determines how this thread interacts with the safepoint handling. */ + private static final FastThreadLocalInt safepointBehaviorTL = FastThreadLocalFactory.createInt("StatusSupport.safepointBehaviorTL"); + + /** The thread will freeze as soon as possible if a safepoint is requested. */ + public static final int ALLOW_SAFEPOINT = 0; + + /** + * The thread won't freeze at a safepoint, and will actively prevent the VM from reaching a + * safepoint (regardless of the thread status). + */ + static final int PREVENT_VM_FROM_REACHING_SAFEPOINT = 1; + + /** + * The thread won't freeze at a safepoint and the safepoint handling will ignore the thread. + * So, the VM will be able to reach a safepoint regardless of the status of this thread. + */ + static final int THREAD_CRASHED = 2; + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static boolean ignoresSafepoints() { + return safepointBehaviorTL.getVolatile() != ALLOW_SAFEPOINT; + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static boolean ignoresSafepoints(IsolateThread vmThread) { + return safepointBehaviorTL.getVolatile(vmThread) != ALLOW_SAFEPOINT; + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static int getSafepointBehaviorVolatile(IsolateThread vmThread) { + return safepointBehaviorTL.getVolatile(vmThread); + } + + /** + * Changes the safepoint behavior so that this thread won't freeze at a safepoint. The + * thread will also actively prevent the VM from reaching a safepoint (regardless of its + * thread status). + * + * NOTE: Be careful with this method and make sure that this thread does not allocate any + * Java objects as this could result deadlocks. This method will only work prevent + * safepoints reliably if it is called from a thread with + * {@link StatusSupport#STATUS_IN_JAVA}. + */ + @Uninterruptible(reason = "Called from uninterruptible code.", callerMustBe = true) + public static void preventSafepoints() { + // It would be nice if we could retire the TLAB here but that wouldn't work reliably. + safepointBehaviorTL.setVolatile(PREVENT_VM_FROM_REACHING_SAFEPOINT); + } + + /** + * Marks the thread as crashed. This method may only be used in places where it is not + * possible to safely detach a thread. + * + * Changes the safepoint behavior so that this thread won't freeze at a safepoint. The + * safepoint handling will ignore the thread so that the VM can reach a safepoint regardless + * of the status of this thread. + * + * NOTE: Be careful with this. If a thread is ignored by the safepoint handling, it means + * that it can continue executing while a safepoint (and therefore a GC) is in progress. So, + * make sure that this thread does not allocate or access any movable heap objects (even + * executing write barriers can already cause issues). + */ + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static void markThreadAsCrashed() { + // It would be nice if we could retire the TLAB here but that wouldn't work reliably. + safepointBehaviorTL.setVolatile(THREAD_CRASHED); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static String toString(int safepointBehavior) { + switch (safepointBehavior) { + case ALLOW_SAFEPOINT: + return "ALLOW_SAFEPOINT"; + case PREVENT_VM_FROM_REACHING_SAFEPOINT: + return "PREVENT_VM_FROM_REACHING_SAFEPOINT"; + case THREAD_CRASHED: + return "THREAD_CRASHED"; + default: + return "Invalid safepoint behavior"; + } + } + } + /** * A thread-local enum conveying any actions needed before thread begins executing Java code. */ public static class ActionOnTransitionToJavaSupport { /** The actions to be performed. */ - private static final FastThreadLocalInt actionTL = FastThreadLocalFactory.createInt(); + private static final FastThreadLocalInt actionTL = FastThreadLocalFactory.createInt("ActionOnTransitionToJavaSupport.actionTL"); /** The thread does not need to take any action. */ private static final int NO_ACTION = 0; @@ -878,7 +936,7 @@ public static void requestAllThreadsSynchronizeCode() { */ public static class ActionOnExitSafepointSupport { - private static final FastThreadLocalInt actionTL = FastThreadLocalFactory.createInt(); + private static final FastThreadLocalInt actionTL = FastThreadLocalFactory.createInt("ActionOnExitSafepointSupport.actionTL"); private static final int NO_ACTION = 0; /** * The thread needs to start execution from a different stack, used for preempting a @@ -887,8 +945,8 @@ public static class ActionOnExitSafepointSupport { private static final int SWITCH_STACK = NO_ACTION + 1; /** Target of stack switching. */ - private static final FastThreadLocalWord returnSP = FastThreadLocalFactory.createWord(); - private static final FastThreadLocalWord returnIP = FastThreadLocalFactory.createWord(); + private static final FastThreadLocalWord returnSP = FastThreadLocalFactory.createWord("ActionOnExitSafepointSupport.returnSP"); + private static final FastThreadLocalWord returnIP = FastThreadLocalFactory.createWord("ActionOnExitSafepointSupport.returnIP"); @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static boolean isActionPending() { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocal.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocal.java index e243629930ec..58d4a2a26a89 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocal.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocal.java @@ -32,8 +32,7 @@ * Base class for fast thread local variables. */ public abstract class FastThreadLocal { - - static class FastThreadLocalLocationIdentity extends LocationIdentity { + class FastThreadLocalLocationIdentity extends LocationIdentity { @Override public boolean isImmutable() { return false; @@ -41,15 +40,18 @@ public boolean isImmutable() { @Override public String toString() { - return "THREAD_LOCAL@" + Integer.toHexString(hashCode()); + return "FastThreadLocal:" + name; } + } private final LocationIdentity locationIdentity; + private final String name; @Platforms(Platform.HOSTED_ONLY.class) - FastThreadLocal() { + FastThreadLocal(String name) { this.locationIdentity = new FastThreadLocalLocationIdentity(); + this.name = name; } /** @@ -122,4 +124,9 @@ public T setAllowFloatingReads(boolean allow) { public boolean getAllowFloatingReads() { return this.allowFloatingReads; } + + public String getName() { + return name; + } + } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalBytes.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalBytes.java index 9c0bd277f9af..1c6c6de2f290 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalBytes.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalBytes.java @@ -49,7 +49,8 @@ public final class FastThreadLocalBytes extends FastThrea private final IntSupplier sizeSupplier; @Platforms(Platform.HOSTED_ONLY.class) - FastThreadLocalBytes(IntSupplier sizeSupplier) { + FastThreadLocalBytes(IntSupplier sizeSupplier, String name) { + super(name); this.sizeSupplier = sizeSupplier; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalFactory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalFactory.java index a731255b7f64..bac87244c121 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalFactory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalFactory.java @@ -68,35 +68,60 @@ private FastThreadLocalFactory() { /** * Creates a new fast thread local variable of the primitive type {@code int}. */ + public static FastThreadLocalInt createInt(String name) { + return new FastThreadLocalInt(name); + } + + @Deprecated public static FastThreadLocalInt createInt() { - return new FastThreadLocalInt(); + return new FastThreadLocalInt("FastThreadLocalInt"); } /** * Creates a new fast thread local variable of the primitive type {@code long}. */ + public static FastThreadLocalLong createLong(String name) { + return new FastThreadLocalLong(name); + } + + @Deprecated public static FastThreadLocalLong createLong() { - return new FastThreadLocalLong(); + return new FastThreadLocalLong("FastThreadLocalLong"); } /** * Creates a new fast thread local variable of type {@link WordBase word}. */ + public static FastThreadLocalWord createWord(String name) { + return new FastThreadLocalWord<>(name); + } + + @Deprecated public static FastThreadLocalWord createWord() { - return new FastThreadLocalWord<>(); + return new FastThreadLocalWord<>("FastThreadLocalWord"); } /** * Creates a new fast thread local variable of type {@link Object}. */ + public static FastThreadLocalObject createObject(Class valueClass, String name) { + return new FastThreadLocalObject<>(valueClass, name); + } + + @Deprecated public static FastThreadLocalObject createObject(Class valueClass) { - return new FastThreadLocalObject<>(valueClass); + return new FastThreadLocalObject<>(valueClass, "FastThreadLocalObject"); } /** * Creates a new fast thread local memory block that has a user-defined size. */ + public static FastThreadLocalBytes createBytes(IntSupplier sizeSupplier, String name) { + return new FastThreadLocalBytes<>(sizeSupplier, name); + } + + @Deprecated public static FastThreadLocalBytes createBytes(IntSupplier sizeSupplier) { - return new FastThreadLocalBytes<>(sizeSupplier); + return new FastThreadLocalBytes<>(sizeSupplier, "FastThreadLocalBytes"); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalInt.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalInt.java index 8061c247cdc5..5612a73ff261 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalInt.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalInt.java @@ -36,7 +36,8 @@ public final class FastThreadLocalInt extends FastThreadLocal { @Platforms(Platform.HOSTED_ONLY.class) - FastThreadLocalInt() { + FastThreadLocalInt(String name) { + super(name); } public int get() { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalLong.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalLong.java index 3cba1561ddd6..c54ecaafe33e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalLong.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalLong.java @@ -36,7 +36,8 @@ public final class FastThreadLocalLong extends FastThreadLocal { @Platforms(Platform.HOSTED_ONLY.class) - FastThreadLocalLong() { + FastThreadLocalLong(String name) { + super(name); } public long get() { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalObject.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalObject.java index 65ed12d1abf7..59956878ffd9 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalObject.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalObject.java @@ -44,7 +44,8 @@ public final class FastThreadLocalObject extends FastThreadLocal { private final Class valueClass; @Platforms(Platform.HOSTED_ONLY.class) - FastThreadLocalObject(Class clazz) { + FastThreadLocalObject(Class clazz, String name) { + super(name); this.valueClass = clazz; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalWord.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalWord.java index e39681199ea1..c07b761f9c63 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalWord.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalWord.java @@ -38,7 +38,8 @@ public final class FastThreadLocalWord extends FastThreadLocal { @Platforms(Platform.HOSTED_ONLY.class) - FastThreadLocalWord() { + FastThreadLocalWord(String name) { + super(name); } public T get() { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfo.java index ef08028e9fc0..fda3e4039cda 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfo.java @@ -36,7 +36,6 @@ import org.graalvm.word.WordBase; import com.oracle.svm.core.FrameAccess; -import com.oracle.svm.core.annotate.UnknownObjectField; import com.oracle.svm.core.annotate.UnknownPrimitiveField; import jdk.vm.ci.meta.JavaKind; @@ -74,8 +73,8 @@ public static Class getValueClass(Class threadLoca public final Class valueClass; public final int maxOffset; public final boolean allowFloatingReads; + public final String name; - @UnknownObjectField(types = {String.class}) public String name; @UnknownPrimitiveField public int offset; @UnknownPrimitiveField public int sizeInBytes; @@ -85,6 +84,7 @@ public VMThreadLocalInfo(FastThreadLocal threadLocal) { this.locationIdentity = threadLocal.getLocationIdentity(); this.maxOffset = threadLocal.getMaxOffset(); this.allowFloatingReads = threadLocal.getAllowFloatingReads(); + this.name = threadLocal.getName(); if (threadLocalClass == FastThreadLocalBytes.class) { sizeSupplier = ((FastThreadLocalBytes) threadLocal).getSizeSupplier(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ImageHeapMap.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ImageHeapMap.java index ff398062c114..654b0206a3c0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ImageHeapMap.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ImageHeapMap.java @@ -29,11 +29,13 @@ import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicMapWrap; +import org.graalvm.collections.Equivalence; import org.graalvm.collections.MapCursor; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.hosted.Feature; +import com.oracle.svm.core.BuildPhaseProvider; import com.oracle.svm.core.annotate.AutomaticFeature; /** @@ -60,7 +62,14 @@ private ImageHeapMap() { */ @Platforms(Platform.HOSTED_ONLY.class) // public static EconomicMap create() { - return new HostedImageHeapMap<>(); + VMError.guarantee(!BuildPhaseProvider.isAnalysisFinished(), "Trying to create an ImageHeapMap after analysis."); + return new HostedImageHeapMap<>(Equivalence.DEFAULT); + } + + @Platforms(Platform.HOSTED_ONLY.class) // + public static EconomicMap create(Equivalence strategy) { + VMError.guarantee(!BuildPhaseProvider.isAnalysisFinished(), "Trying to create an ImageHeapMap after analysis."); + return new HostedImageHeapMap<>(strategy); } } @@ -69,17 +78,15 @@ final class HostedImageHeapMap extends EconomicMapWrap { final EconomicMap runtimeMap; - HostedImageHeapMap() { + HostedImageHeapMap(Equivalence strategy) { super(new ConcurrentHashMap<>()); - this.runtimeMap = EconomicMap.create(); + this.runtimeMap = EconomicMap.create(strategy); } } @AutomaticFeature final class ImageHeapMapFeature implements Feature { - private boolean afterAnalysis; - private final Set> allInstances = ConcurrentHashMap.newKeySet(); @Override @@ -90,7 +97,7 @@ public void duringSetup(DuringSetupAccess config) { private Object imageHeapMapTransformer(Object obj) { if (obj instanceof HostedImageHeapMap) { HostedImageHeapMap hostedImageHeapMap = (HostedImageHeapMap) obj; - if (afterAnalysis) { + if (BuildPhaseProvider.isAnalysisFinished()) { VMError.guarantee(allInstances.contains(hostedImageHeapMap), "ImageHeapMap reachable after analysis that was not seen during analysis"); } else { allInstances.add(hostedImageHeapMap); @@ -110,11 +117,6 @@ public void duringAnalysis(DuringAnalysisAccess access) { } } - @Override - public void afterAnalysis(AfterAnalysisAccess access) { - afterAnalysis = true; - } - @Override public void afterImageWrite(AfterImageWriteAccess access) { for (HostedImageHeapMap hostedImageHeapMap : allInstances) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/UnsignedUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/UnsignedUtils.java index 0cd33267c675..1036a923e006 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/UnsignedUtils.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/UnsignedUtils.java @@ -113,6 +113,7 @@ public static int safeToInt(UnsignedWord w) { @Uninterruptible(reason = "Used in uninterruptible code.", mayBeInlined = true) public static UnsignedWord clamp(UnsignedWord value, UnsignedWord min, UnsignedWord max) { + assert min.belowOrEqual(max); return min(max(value, min), max); } diff --git a/substratevm/src/com.oracle.svm.driver/resources/META-INF/native-image/com.oracle.substratevm/svm-driver/native-image.properties b/substratevm/src/com.oracle.svm.driver/resources/META-INF/native-image/com.oracle.substratevm/svm-driver/native-image.properties index a3883325fe9c..f9acfcc2f4c8 100644 --- a/substratevm/src/com.oracle.svm.driver/resources/META-INF/native-image/com.oracle.substratevm/svm-driver/native-image.properties +++ b/substratevm/src/com.oracle.svm.driver/resources/META-INF/native-image/com.oracle.substratevm/svm-driver/native-image.properties @@ -1,2 +1,2 @@ ImageName = native-image -Args = -H:-ParseRuntimeOptions --initialize-at-build-time=com.oracle.svm.driver +Args = -H:+UseReferenceHandlerThread -H:-ParseRuntimeOptions --initialize-at-build-time=com.oracle.svm.driver diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/APIOptionHandler.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/APIOptionHandler.java index 8c52503484ae..987c8340a069 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/APIOptionHandler.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/APIOptionHandler.java @@ -106,20 +106,15 @@ boolean isDeprecated() { groupInfos = support.groupInfos; apiOptions = support.options; } else { - List> optionDescriptorsList = new ArrayList<>(); - ServiceLoader serviceLoader = ServiceLoader.load(OptionDescriptors.class, nativeImage.getClass().getClassLoader()); - for (OptionDescriptors optionDescriptors : serviceLoader) { - optionDescriptorsList.add(optionDescriptors.getClass()); - } groupInfos = new HashMap<>(); - apiOptions = extractOptions(optionDescriptorsList, groupInfos); + apiOptions = extractOptions(ServiceLoader.load(OptionDescriptors.class, nativeImage.getClass().getClassLoader()), groupInfos); } } - static SortedMap extractOptions(List> optionsClasses, Map groupInfos) { + static SortedMap extractOptions(ServiceLoader optionDescriptors, Map groupInfos) { EconomicMap hostedOptions = EconomicMap.create(); EconomicMap runtimeOptions = EconomicMap.create(); - HostedOptionParser.collectOptions(optionsClasses, hostedOptions, runtimeOptions); + HostedOptionParser.collectOptions(optionDescriptors, hostedOptions, runtimeOptions); SortedMap apiOptions = new TreeMap<>(); Map, APIOptionGroup> groupInstances = new HashMap<>(); hostedOptions.getValues().forEach(o -> extractOption(NativeImage.oH, o, apiOptions, groupInfos, groupInstances)); @@ -450,9 +445,9 @@ final class APIOptionFeature implements Feature { @Override public void duringSetup(DuringSetupAccess access) { FeatureImpl.DuringSetupAccessImpl accessImpl = (FeatureImpl.DuringSetupAccessImpl) access; - List> optionClasses = accessImpl.getImageClassLoader().findSubclasses(OptionDescriptors.class, true); Map groupInfos = new HashMap<>(); - SortedMap options = APIOptionHandler.extractOptions(optionClasses, groupInfos); + ServiceLoader optionDescriptors = ServiceLoader.load(OptionDescriptors.class, accessImpl.getImageClassLoader().getClassLoader()); + SortedMap options = APIOptionHandler.extractOptions(optionDescriptors, groupInfos); ImageSingletons.add(APIOptionSupport.class, new APIOptionSupport(groupInfos, options)); } } diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index ba01e3d1a970..c4baa36c843d 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java @@ -50,6 +50,7 @@ import java.util.Map; import java.util.Optional; import java.util.Properties; +import java.util.StringJoiner; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -63,6 +64,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import com.oracle.svm.common.option.CommonOptions; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.nativeimage.Platform; @@ -90,8 +92,6 @@ public class NativeImage { - private static final String ENV_VAR_USE_MODULE_SYSTEM = "USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM"; - private static final String DEFAULT_GENERATOR_CLASS_NAME = NativeImageGeneratorRunner.class.getName(); private static final String DEFAULT_GENERATOR_MODULE_NAME = ModuleSupport.getModuleName(NativeImageGeneratorRunner.class); @@ -189,8 +189,8 @@ void addFallbackBuildArgs(@SuppressWarnings("unused") List buildArgs) { public static final String oH = "-H:"; static final String oR = "-R:"; - final String enablePrintFlags = SubstrateOptions.PrintFlags.getName(); - final String enablePrintFlagsWithExtraHelp = SubstrateOptions.PrintFlagsWithExtraHelp.getName(); + final String enablePrintFlags = CommonOptions.PrintFlags.getName(); + final String enablePrintFlagsWithExtraHelp = CommonOptions.PrintFlagsWithExtraHelp.getName(); private static String oH(OptionKey option) { return oH + option.getName() + "="; @@ -279,7 +279,7 @@ protected BuildConfiguration(List args) { @SuppressWarnings("deprecation") BuildConfiguration(Path rootDir, Path workDir, List args) { - modulePathBuild = Boolean.parseBoolean(System.getenv().get(ENV_VAR_USE_MODULE_SYSTEM)); + modulePathBuild = Boolean.parseBoolean(System.getenv().get(ModuleSupport.ENV_VAR_USE_MODULE_SYSTEM)); this.args = args; this.workDir = workDir != null ? workDir : Paths.get(".").toAbsolutePath().normalize(); if (rootDir != null) { @@ -1301,7 +1301,22 @@ protected static List createImageBuilderArgs(ArrayList imageArgs protected static String createVMInvocationArgumentFile(List arguments) { try { Path argsFile = Files.createTempFile("vminvocation", ".args"); - String joinedOptions = String.join("\n", arguments); + StringJoiner joiner = new StringJoiner("\n"); + for (String arg : arguments) { + // Options in @argfile need to be properly quoted as + // this relies on the JDK's @argfile parsing when the + // native image generator is being launched. + String quoted = SubstrateUtil.quoteShellArg(arg); + // @argfile rules for Windows quirk: backslashes don't need to be + // escaped if the option they are used in isn't quoted. If it is + // though, then they need to be escaped. This might mean that + // user-supplied arguments containing '\' will be double escaped. + if (quoted.startsWith("'")) { + quoted = quoted.replace("\\", "\\\\"); + } + joiner.add(quoted); + } + String joinedOptions = joiner.toString(); Files.write(argsFile, joinedOptions.getBytes()); argsFile.toFile().deleteOnExit(); return "@" + argsFile; @@ -1385,7 +1400,7 @@ protected int buildImage(List javaArgs, LinkedHashSet bcp, LinkedH ProcessBuilder pb = new ProcessBuilder(); pb.command(command); if (config.modulePathBuild) { - pb.environment().put(ENV_VAR_USE_MODULE_SYSTEM, Boolean.toString(true)); + pb.environment().put(ModuleSupport.ENV_VAR_USE_MODULE_SYSTEM, Boolean.toString(true)); } p = pb.inheritIO().start(); exitStatus = p.waitFor(); @@ -1790,7 +1805,7 @@ protected String getXmsValue() { return "1g"; } - @SuppressWarnings("deprecation") // getTotalPhysicalMemorySize deprecated since JDK 14 + @SuppressWarnings("deprecation") // getTotalPhysicalMemorySize is deprecated after JDK 11 private static long getPhysicalMemorySize() { OperatingSystemMXBean osMXBean = ManagementFactory.getOperatingSystemMXBean(); long totalPhysicalMemorySize = ((com.sun.management.OperatingSystemMXBean) osMXBean).getTotalPhysicalMemorySize(); @@ -1859,7 +1874,7 @@ static String resolvePropertyValue(String val, String optionArg, Path componentD * substitutions of kind ${} -> on resultVal. */ for (String argNameValue : optionArg.split(",")) { - String[] splitted = argNameValue.split(":"); + String[] splitted = argNameValue.split(":", 2); if (splitted.length == 2) { String argName = splitted[0]; String argValue = splitted[1]; diff --git a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalEntryPoints.java b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalEntryPoints.java index d84475bac3cb..90d9a658186a 100644 --- a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalEntryPoints.java +++ b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalEntryPoints.java @@ -60,7 +60,6 @@ import com.oracle.svm.core.c.CGlobalData; import com.oracle.svm.core.c.CGlobalDataFactory; -import com.oracle.svm.core.c.function.CEntryPointOptions; import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.hotspot.HotSpotCompilationRequest; @@ -176,7 +175,9 @@ public static long getIsolateId(PointerBase jniEnv, * {@code org.graalvm.compiler.hotspot.test.CompileTheWorld.compileMethodInLibgraal()}. * * @param methodHandle the method to be compiled. This is a handle to a - * {@link HotSpotResolvedJavaMethod} in HotSpot's heap. + * {@link HotSpotResolvedJavaMethod} in HotSpot's heap. A value of 0L can be passed + * to use this method for the side effect of initializing a + * {@link HotSpotGraalCompiler} instance without doing any compilation. * @param useProfilingInfo specifies if profiling info should be used during the compilation * @param installAsDefault specifies if the compiled code should be installed for the * {@code Method*} associated with {@code methodHandle} @@ -202,8 +203,7 @@ public static long getIsolateId(PointerBase jniEnv, * @return a handle to a {@link InstalledCode} in HotSpot's heap or 0 if compilation failed */ @SuppressWarnings({"unused", "try"}) - @CEntryPoint(name = "Java_org_graalvm_compiler_hotspot_test_CompileTheWorld_compileMethodInLibgraal") - @CEntryPointOptions(include = LibGraalFeature.IsEnabled.class) + @CEntryPoint(name = "Java_org_graalvm_compiler_hotspot_test_CompileTheWorld_compileMethodInLibgraal", include = LibGraalFeature.IsEnabled.class) private static long compileMethod(PointerBase jniEnv, PointerBase jclass, @CEntryPoint.IsolateThreadContext long isolateThread, @@ -218,11 +218,14 @@ private static long compileMethod(PointerBase jniEnv, int stackTraceCapacity) { try { HotSpotJVMCIRuntime runtime = runtime(); + HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) runtime.getCompiler(); + if (methodHandle == 0L) { + return 0L; + } HotSpotResolvedJavaMethod method = LibGraal.unhand(HotSpotResolvedJavaMethod.class, methodHandle); int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI; HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, entryBCI, 0L); - HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) runtime.getCompiler(); try (CompilationContext scope = HotSpotGraalServices.openLocalCompilationContext(request)) { OptionValues options = decodeOptions(optionsAddress, optionsSize, optionsHash); diff --git a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java index 4bbca94734b4..3d3faf79e2ad 100644 --- a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java +++ b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java @@ -99,6 +99,7 @@ import org.graalvm.compiler.truffle.runtime.GraalTruffleRuntime; import org.graalvm.libgraal.LibGraal; import org.graalvm.libgraal.jni.LibGraalNativeBridgeSupport; +import org.graalvm.libgraal.jni.LibGraalUtil; import org.graalvm.nativebridge.jni.JNI; import org.graalvm.nativebridge.jni.JNIExceptionWrapper; import org.graalvm.nativebridge.jni.JNIMethodScope; @@ -166,6 +167,10 @@ class LibGraalOptions { "if a non-null pointer was passed in the _fatal option to JNI_CreateJavaVM. " + "This option exists for the purpose of testing fatal error handling in libgraal.") static final RuntimeOptionKey CrashAtIsFatal = new RuntimeOptionKey<>(false); + @Option(help = "The fully qualified name of a no-arg, void, static method to be invoked " + + "in HotSpot from libgraal when the libgraal isolate is being shutdown." + + "This option exists for the purpose of testing callbacks in this context.") + static final RuntimeOptionKey OnShutdownCallback = new RuntimeOptionKey<>(null); // @formatter:on } @@ -645,7 +650,7 @@ private static CompilationRequestResult compileMethod(HotSpotGraalCompiler compi // This scope is required to allow Graal compilations of host methods to call methods // on the TruffleCompilerRuntime. This is, for example, required to find out about // Truffle-specific method annotations. - try (JNIMethodScope scope = new JNIMethodScope("", env)) { + try (JNIMethodScope scope = LibGraalUtil.openScope("", env)) { return compiler.compileMethod(request, true, compiler.getGraalRuntime().getOptions()); } } @@ -678,7 +683,7 @@ public Object compute(MetaAccessProvider metaAccess, ResolvedJavaField original, @Substitute private static void shutdownLibGraal(HotSpotGraalRuntime runtime) { try { - // Unregister this isolate if it was create as a peer + // Unregister this isolate if it was created as a peer if (LibGraalEntryPoints.hasLibGraalIsolatePeer()) { long offset = runtime.getVMConfig().jniEnvironmentOffset; long javaThreadAddr = HotSpotJVMCIRuntime.runtime().getCurrentJavaThread(); @@ -690,6 +695,21 @@ private static void shutdownLibGraal(HotSpotGraalRuntime runtime) { args.setLong(IsolateUtil.getIsolateID()); env.getFunctions().getCallStaticVoidMethodA().call(env, libGraalIsolateClass, unregisterMethod, args); JNIExceptionWrapper.wrapAndThrowPendingJNIException(env); + + String callback = LibGraalOptions.OnShutdownCallback.getValue(); + if (callback != null) { + int lastDot = callback.lastIndexOf('.'); + if (lastDot < 1 || lastDot == callback.length() - 1) { + throw new IllegalArgumentException(LibGraalOptions.OnShutdownCallback.getName() + " value does not have . format: " + callback); + } + String cbClassName = callback.substring(0, lastDot); + String cbMethodName = callback.substring(lastDot + 1); + JNI.JClass cbClass = JNIUtil.findClass(env, JNIUtil.getSystemClassLoader(env), + JNIUtil.getBinaryName(cbClassName), true); + JNI.JMethodID cbMethod = JNIUtil.findMethod(env, cbClass, true, cbMethodName, "()V"); + env.getFunctions().getCallStaticVoidMethodA().call(env, cbClass, cbMethod, StackValue.get(0)); + JNIExceptionWrapper.wrapAndThrowPendingJNIException(env); + } } } catch (Throwable t) { t.printStackTrace(TTY.out); diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSupport.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSupport.java index 1c99945a3aa9..94af62be2e31 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSupport.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSupport.java @@ -293,7 +293,7 @@ public static EncodedGraph encodedGraph(SharedRuntimeMethod method, boolean trac if (startOffset == -1) { return null; } - return new EncodedGraph(get().graphEncoding, startOffset, get().graphObjects, get().graphNodeTypes, null, null, null, false, trackNodeSourcePosition); + return new EncodedGraph(get().graphEncoding, startOffset, get().graphObjects, get().graphNodeTypes, null, null, false, trackNodeSourcePosition); } public static StructuredGraph decodeGraph(DebugContext debug, String name, CompilationIdentifier compilationId, SharedRuntimeMethod method) { diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/DeoptimizationFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/DeoptimizationFeature.java index 3fee955d70b4..0180a73028dd 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/DeoptimizationFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/DeoptimizationFeature.java @@ -126,6 +126,6 @@ public void beforeCompilation(BeforeCompilationAccess a) { CompilationAccessImpl config = (CompilationAccessImpl) a; config.registerAsImmutable(ImageSingletons.lookup(DeoptimizationSupport.class)); HostedMetaAccess metaAccess = config.getMetaAccess(); - DeoptimizationSupport.setDeoptStubPointer(MethodPointer.factory(metaAccess.lookupJavaMethod(deoptStubMethod))); + DeoptimizationSupport.setDeoptStubPointer(new MethodPointer(metaAccess.lookupJavaMethod(deoptStubMethod))); } } diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalFeature.java index 07ae77437477..d046c5c7f9f1 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalFeature.java @@ -89,6 +89,7 @@ import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.HostedProviders; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; @@ -120,7 +121,6 @@ import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl; import com.oracle.svm.hosted.NativeImageGenerator; import com.oracle.svm.hosted.analysis.Inflation; -import com.oracle.svm.hosted.c.GraalAccess; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.code.CompilationInfoSupport; import com.oracle.svm.hosted.code.SharedRuntimeConfigurationBuilder; @@ -735,7 +735,7 @@ private static void removeUnreachableInvokes(CallTreeNode node) { InliningUtil.nonNullReceiver(invoke); } FixedGuardNode guard = new FixedGuardNode(LogicConstantNode.forBoolean(true, node.graph), DeoptimizationReason.UnreachedCode, DeoptimizationAction.None, true); - node.graph.addBeforeFixed(invoke.asNode(), node.graph.add(guard)); + node.graph.addBeforeFixed(invoke.asFixedNode(), node.graph.add(guard)); } } diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalObjectReplacer.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalObjectReplacer.java index bc178efa1188..76dcd99d9580 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalObjectReplacer.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalObjectReplacer.java @@ -64,7 +64,7 @@ import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.ameta.AnalysisConstantFieldProvider; import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; -import com.oracle.svm.hosted.analysis.NativeImagePointsToAnalysis; +import com.oracle.svm.hosted.analysis.AnnotationsProcessor; import com.oracle.svm.hosted.meta.HostedConstantFieldProvider; import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedMethod; @@ -217,7 +217,7 @@ public synchronized SubstrateMethod createMethod(ResolvedJavaMethod original) { * Annotations are updated in every analysis iteration, but this is a starting point. It * also ensures that all types used by annotations are created eagerly. */ - sMethod.setAnnotationsEncoding(NativeImagePointsToAnalysis.encodeAnnotations(aMetaAccess, aMethod.getAnnotations(), aMethod.getDeclaredAnnotations(), null)); + sMethod.setAnnotationsEncoding(AnnotationsProcessor.encodeAnnotations(aMetaAccess, aMethod.getAnnotations(), aMethod.getDeclaredAnnotations(), null)); } return sMethod; } @@ -251,7 +251,7 @@ public synchronized SubstrateField createField(ResolvedJavaField original) { * Annotations are updated in every analysis iteration, but this is a starting point. It * also ensures that all types used by annotations are created eagerly. */ - sField.setAnnotationsEncoding(NativeImagePointsToAnalysis.encodeAnnotations(aMetaAccess, aField.getAnnotations(), aField.getDeclaredAnnotations(), null)); + sField.setAnnotationsEncoding(AnnotationsProcessor.encodeAnnotations(aMetaAccess, aField.getAnnotations(), aField.getDeclaredAnnotations(), null)); } return sField; } @@ -378,13 +378,13 @@ public boolean updateDataDuringAnalysis(AnalysisMetaAccess metaAccess) { } for (Map.Entry entry : methods.entrySet()) { - if (entry.getValue().setAnnotationsEncoding(NativeImagePointsToAnalysis.encodeAnnotations(metaAccess, entry.getKey().getAnnotations(), entry.getKey().getDeclaredAnnotations(), + if (entry.getValue().setAnnotationsEncoding(AnnotationsProcessor.encodeAnnotations(metaAccess, entry.getKey().getAnnotations(), entry.getKey().getDeclaredAnnotations(), entry.getValue().getAnnotationsEncoding()))) { result = true; } } for (Map.Entry entry : fields.entrySet()) { - if (entry.getValue().setAnnotationsEncoding(NativeImagePointsToAnalysis.encodeAnnotations(metaAccess, entry.getKey().getAnnotations(), entry.getKey().getDeclaredAnnotations(), + if (entry.getValue().setAnnotationsEncoding(AnnotationsProcessor.encodeAnnotations(metaAccess, entry.getKey().getAnnotations(), entry.getKey().getDeclaredAnnotations(), entry.getValue().getAnnotationsEncoding()))) { result = true; } diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareConstantReflectionProvider.java index 3b2ab8058d84..f928c83d731a 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareConstantReflectionProvider.java @@ -85,8 +85,8 @@ private static JavaConstant read(JavaKind kind, Constant base, long displacement return ConstantDataConverter.toCompiler(resultData); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void read0(@SuppressWarnings("unused") ClientIsolateThread client, char kindChar, ConstantData baseData, long displacement, int primitiveBits, long compressBase, int compressShift, ConstantData resultData) { JavaConstant base = ConstantDataConverter.toClient(baseData); @@ -131,8 +131,8 @@ public Integer readArrayLength(JavaConstant array) { return Array.getLength(arrayObj); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static int readArrayLength0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle arrayHandle) { Object array = IsolatedCompileClient.get().unhand(arrayHandle); if (!array.getClass().isArray()) { @@ -156,8 +156,8 @@ public JavaConstant readArrayElement(JavaConstant array, int index) { return ConstantDataConverter.toCompiler(resultData); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void readArrayElement0(@SuppressWarnings("unused") ClientIsolateThread client, ConstantData arrayData, int index, ConstantData resultData) { JavaConstant array = ConstantDataConverter.toClient(arrayData); Object a = SubstrateObjectConstant.asObject(array); @@ -185,8 +185,8 @@ public JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receive return ConstantDataConverter.toCompiler(resultData); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void readFieldValue0(@SuppressWarnings("unused") ClientIsolateThread client, ImageHeapRef fieldRef, ConstantData receiverData, ConstantData resultData) { JavaConstant receiver = ConstantDataConverter.toClient(receiverData); Constant result = readFieldValue(ImageHeapObjects.deref(fieldRef), receiver); @@ -208,8 +208,8 @@ public JavaConstant boxPrimitive(JavaConstant primitive) { return ConstantDataConverter.toCompiler(resultData); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void boxPrimitive0(@SuppressWarnings("unused") ClientIsolateThread client, ConstantData primitiveData, ConstantData resultData) { JavaConstant primitive = ConstantDataConverter.toClient(primitiveData); Constant result = SubstrateObjectConstant.forObject(primitive.asBoxedPrimitive()); @@ -229,8 +229,8 @@ public JavaConstant unboxPrimitive(JavaConstant boxed) { return super.unboxPrimitive(boxed); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void unboxPrimitive0(@SuppressWarnings("unused") ClientIsolateThread client, ConstantData boxedData, ConstantData resultData) { Constant boxed = ConstantDataConverter.toClient(boxedData); Constant result = JavaConstant.forBoxedPrimitive(SubstrateObjectConstant.asObject(boxed)); @@ -254,8 +254,8 @@ public ResolvedJavaType asJavaType(Constant hub) { return super.asJavaType(resolved); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ImageHeapRef getHubConstantAsImageHeapRef(@SuppressWarnings("unused") ClientIsolateThread client, ConstantData hubData) { JavaConstant hub = ConstantDataConverter.toClient(hubData); Object target = SubstrateObjectConstant.asObject(hub); @@ -283,8 +283,8 @@ public int getImageHeapOffset(JavaConstant constant) { return super.getImageHeapOffset(constant); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static int getImageHeapOffset0(@SuppressWarnings("unused") ClientIsolateThread client, ConstantData constantData) { Constant constant = ConstantDataConverter.toClient(constantData); return getImageHeapOffsetInternal((SubstrateObjectConstant) constant); diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareObjectConstantEqualityFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareObjectConstantEqualityFeature.java index 32176312fc61..bd73afd2c54e 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareObjectConstantEqualityFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareObjectConstantEqualityFeature.java @@ -65,14 +65,14 @@ private static boolean compareIsolatedConstant(IsolatedObjectConstant a, Constan throw VMError.shouldNotReachHere("Unknown object constant: " + b); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) static boolean isolatedConstantHandleTargetsEqual(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle x, ClientHandle y) { return IsolatedCompileClient.get().unhand(x) == IsolatedCompileClient.get().unhand(y); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static boolean isolatedHandleTargetEqualImageObject(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle x, ImageHeapRef y) { return IsolatedCompileClient.get().unhand(x) == ImageHeapObjects.deref(y); } diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedCompileClient.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedCompileClient.java index 20ffe9e193cb..2483a24f3f66 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedCompileClient.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedCompileClient.java @@ -44,7 +44,7 @@ public final class IsolatedCompileClient { private static final FastThreadLocalObject currentClient = // - FastThreadLocalFactory.createObject(IsolatedCompileClient.class); + FastThreadLocalFactory.createObject(IsolatedCompileClient.class, "IsolatedCompileClient.currentClient"); @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static IsolatedCompileClient get() { @@ -87,8 +87,8 @@ public CompilerHandle createStringInCompiler(String s) { } } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static CompilerHandle createStringInCompiler0(@SuppressWarnings("unused") CompilerIsolateThread compiler, CCharPointer cstr) { return IsolatedCompileContext.get().hand(CTypeConversion.toJavaString(cstr)); } diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedCompileContext.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedCompileContext.java index d286403f4e25..c4e58c8ec915 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedCompileContext.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedCompileContext.java @@ -44,7 +44,7 @@ */ public final class IsolatedCompileContext { private static final FastThreadLocalObject currentContext = // - FastThreadLocalFactory.createObject(IsolatedCompileContext.class); + FastThreadLocalFactory.createObject(IsolatedCompileContext.class, "IsolatedCompileContext.currentContext"); public static IsolatedCompileContext get() { return currentContext.get(); @@ -88,14 +88,14 @@ public ClientHandle createStringArrayInClient(String[] array) { } } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ClientHandle createStringInClient0(@SuppressWarnings("unused") ClientIsolateThread client, CCharPointer cstr) { return IsolatedCompileClient.get().hand(CTypeConversion.toJavaString(cstr)); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ClientHandle createStringArrayInClient0(@SuppressWarnings("unused") ClientIsolateThread client, int length, CCharPointerPointer ptrs) { String[] array = new String[length]; for (int i = 0; i < length; i++) { diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedGraalUtils.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedGraalUtils.java index b15a60762744..04cd8adca1ca 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedGraalUtils.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedGraalUtils.java @@ -78,8 +78,8 @@ public static InstalledCode compileInNewIsolateAndInstall(SubstrateMethod method return installedCode; } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ClientHandle compileInNewIsolateAndInstall0(@SuppressWarnings("unused") @CEntryPoint.IsolateThreadContext CompilerIsolateThread isolate, ClientIsolateThread clientIsolate, ImageHeapRef methodRef, ClientHandle encodedOptions, int encodedOptionsLength) { @@ -115,8 +115,8 @@ public static void compileInNewIsolate(SubstrateMethod method) { } } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void compileInNewIsolate0(@SuppressWarnings("unused") @CEntryPoint.IsolateThreadContext CompilerIsolateThread isolate, ClientIsolateThread clientIsolate, ImageHeapRef methodRef, ClientHandle encodedOptions, int encodedOptionsLength) { @@ -158,8 +158,8 @@ public static void applyClientRuntimeOptionValues(ClientHandle encodedOp } } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void copyOptions(@SuppressWarnings("unused") @CEntryPoint.IsolateThreadContext ClientIsolateThread isolate, ClientHandle encodedOptionsHandle, PointerBase buffer) { byte[] encodedOptions = IsolatedCompileClient.get().unhand(encodedOptionsHandle); CTypeConversion.asByteBuffer(buffer, encodedOptions.length).put(encodedOptions); diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedObjectConstant.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedObjectConstant.java index 3ed71f59624c..7e4190067799 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedObjectConstant.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedObjectConstant.java @@ -63,8 +63,8 @@ private Class getObjectClass() { return cachedClass; } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ImageHeapRef> getObjectClass0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle h) { Object target = IsolatedCompileClient.get().unhand(h); return ImageHeapObjects.ref(target.getClass()); @@ -98,8 +98,8 @@ public int getIdentityHashCode() { return h; } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static int getIdentityHashCode0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle h) { Object target = IsolatedCompileClient.get().unhand(h); return computeIdentityHashCode(target); diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedObjectProxy.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedObjectProxy.java index 915d4fe9d009..ca8d5a8dfcbc 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedObjectProxy.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedObjectProxy.java @@ -81,14 +81,14 @@ public String toString() { return s; } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static int hashCode0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle handle) { return IsolatedCompileClient.get().unhand(handle).hashCode(); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static CompilerHandle toString0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle handle) { Object obj = IsolatedCompileClient.get().unhand(handle); String s = "Isolated: " + obj; diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedRuntimeCodeInstaller.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedRuntimeCodeInstaller.java index 5326f0b09add..7a7a1a284fe8 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedRuntimeCodeInstaller.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedRuntimeCodeInstaller.java @@ -60,8 +60,8 @@ public static ClientHandle installInClientIsolate(ImageH return installInClientIsolate0(clientIsolate, methodRef, installInfo, installedCodeFactoryHandle); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ClientHandle installInClientIsolate0(@SuppressWarnings("unused") @CEntryPoint.IsolateThreadContext ClientIsolateThread isolate, ImageHeapRef methodRef, CodeInstallInfo installInfo, ClientHandle installedCodeFactoryHandle) { @@ -92,8 +92,8 @@ public static ClientHandle installInClientIsolate(Shared return installInClientIsolate1(clientIsolate, clientMethodHandle, installInfo, installedCodeFactoryHandle); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ClientHandle installInClientIsolate1(@SuppressWarnings("unused") @CEntryPoint.IsolateThreadContext ClientIsolateThread isolate, ClientHandle methodHandle, CodeInstallInfo installInfo, ClientHandle installedCodeFactoryHandle) { @@ -154,8 +154,8 @@ protected Pointer allocateCodeMemory(long size) { return (Pointer) memory; } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static CodePointer allocateCodeMemory0(@SuppressWarnings("unused") IsolateThread targetIsolate, UnsignedWord size) { return RuntimeCodeInfoAccess.allocateCodeMemory(size); } @@ -165,8 +165,8 @@ protected void makeCodeMemoryReadOnly(Pointer start, long size) { makeCodeMemoryReadOnly0(targetIsolate, start, size); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void makeCodeMemoryReadOnly0(@SuppressWarnings("unused") IsolateThread targetIsolate, Pointer start, long size) { RuntimeCodeInfoAccess.makeCodeMemoryExecutableReadOnly((CodePointer) start, WordFactory.unsigned(size)); } @@ -176,8 +176,8 @@ protected void makeCodeMemoryWriteableNonExecutable(Pointer start, long size) { makeCodeMemoryWriteableNonExecutable0(targetIsolate, start, size); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void makeCodeMemoryWriteableNonExecutable0(@SuppressWarnings("unused") IsolateThread targetIsolate, Pointer start, long size) { RuntimeCodeInfoAccess.makeCodeMemoryWriteableNonExecutable((CodePointer) start, WordFactory.unsigned(size)); } diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedSpeculationLog.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedSpeculationLog.java index 7dde34be0877..058f5058b007 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedSpeculationLog.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolatedSpeculationLog.java @@ -159,20 +159,20 @@ public Speculation lookupSpeculation(JavaConstant constant) { throw VMError.shouldNotReachHere("not required"); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void collectFailedSpeculations0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle logHandle) { IsolatedCompileClient.get().unhand(logHandle).collectFailedSpeculations(); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static boolean hasSpeculations0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle logHandle) { return IsolatedCompileClient.get().unhand(logHandle).hasSpeculations(); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static boolean maySpeculate0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle logHandle, PointerBase arrayData, int length) { byte[] bytes = new byte[length]; ByteBuffer.wrap(bytes).put(CTypeConversion.asByteBuffer(arrayData, length)); @@ -180,8 +180,8 @@ private static boolean maySpeculate0(@SuppressWarnings("unused") ClientIsolateTh return log.maySpeculate(new EncodedSpeculationReason(bytes)); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ClientHandle speculate0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle logHandle, PointerBase arrayData, int length) { byte[] bytes = new byte[length]; ByteBuffer.wrap(bytes).put(CTypeConversion.asByteBuffer(arrayData, length)); diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/RuntimeCodeInstaller.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/RuntimeCodeInstaller.java index d643c805100d..19a77c99f852 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/RuntimeCodeInstaller.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/RuntimeCodeInstaller.java @@ -26,8 +26,10 @@ import java.nio.ByteBuffer; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import jdk.vm.ci.meta.ResolvedJavaMethod; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.code.CompilationResult.CodeAnnotation; import org.graalvm.compiler.core.common.NumUtil; @@ -192,10 +194,12 @@ protected void doPrepareInstall(ReferenceAdjuster adjuster, CodeInfo codeInfo) { Map patches = new HashMap<>(); for (CodeAnnotation codeAnnotation : compilation.getCodeAnnotations()) { if (codeAnnotation instanceof NativeImagePatcher) { - patches.put(codeAnnotation.getPosition(), (NativeImagePatcher) codeAnnotation); + NativeImagePatcher priorValue = patches.put(codeAnnotation.getPosition(), (NativeImagePatcher) codeAnnotation); + VMError.guarantee(priorValue == null, "Registering two patchers for same position."); } } - patchData(patches, objectConstants); + int numPatchesHandled = patchData(patches, objectConstants); + VMError.guarantee(numPatchesHandled == patches.size(), "Not all patches applied."); // Store the compiled code for (int index = 0; index < codeSize; index++) { @@ -241,7 +245,7 @@ private void patchDirectObjectConstants(ObjectConstantsHolder objectConstants, C } private void createCodeChunkInfos(CodeInfo runtimeMethodInfo, ReferenceAdjuster adjuster) { - CodeInfoEncoder codeInfoEncoder = new CodeInfoEncoder(new FrameInfoEncoder.NamesFromImage()); + CodeInfoEncoder codeInfoEncoder = new CodeInfoEncoder(new RuntimeFrameInfoCustomization()); codeInfoEncoder.addMethod(method, compilation, 0); codeInfoEncoder.encodeAllAndInstall(runtimeMethodInfo, adjuster); @@ -252,18 +256,43 @@ private void createCodeChunkInfos(CodeInfo runtimeMethodInfo, ReferenceAdjuster sourcePositionEncoder.encodeAndInstall(compilation.getDeoptimizationSourcePositions(), runtimeMethodInfo, adjuster); } - private void patchData(Map patcher, @SuppressWarnings("unused") ObjectConstantsHolder objectConstants) { + private int patchData(Map patcher, ObjectConstantsHolder objectConstants) { + int patchesHandled = 0; + HashSet patchedOffsets = new HashSet<>(); for (DataPatch dataPatch : compilation.getDataPatches()) { NativeImagePatcher patch = patcher.get(dataPatch.pcOffset); + boolean noPriorMatch = patchedOffsets.add(dataPatch.pcOffset); + VMError.guarantee(noPriorMatch, "Patching same offset twice."); + patchesHandled++; if (dataPatch.reference instanceof DataSectionReference) { DataSectionReference ref = (DataSectionReference) dataPatch.reference; int pcDisplacement = dataOffset + ref.getOffset() - dataPatch.pcOffset; - patch.patchCode(pcDisplacement, compiledBytes); + patch.patchCode(code.rawValue(), pcDisplacement, compiledBytes); } else if (dataPatch.reference instanceof ConstantReference) { ConstantReference ref = (ConstantReference) dataPatch.reference; SubstrateObjectConstant refConst = (SubstrateObjectConstant) ref.getConstant(); objectConstants.add(patch.getOffset(), patch.getLength(), refConst); + } else { + throw VMError.shouldNotReachHere("Unhandled data patch."); } } + return patchesHandled; + } + + private static class RuntimeFrameInfoCustomization extends FrameInfoEncoder.SourceFieldsFromImage { + @Override + protected boolean storeDeoptTargetMethod() { + return true; + } + + @Override + protected boolean includeLocalValues(ResolvedJavaMethod method, Infopoint infopoint) { + return true; + } + + @Override + protected boolean isDeoptEntry(ResolvedJavaMethod method, Infopoint infopoint) { + return false; + } } } diff --git a/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/ModuleLayerFeature.java b/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/ModuleLayerFeature.java index 187c7037b11c..3f0c27bec9d0 100644 --- a/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/ModuleLayerFeature.java +++ b/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/ModuleLayerFeature.java @@ -29,6 +29,7 @@ import com.oracle.svm.core.jdk11.BootModuleLayerSupport; import com.oracle.svm.core.jdk.JDK11OrLater; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.util.ModuleSupport; import com.oracle.svm.util.ReflectionUtil; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; @@ -45,25 +46,32 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Optional; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * This feature: *
      - *
    • synthesizes the runtime boot module layer
    • - *
    • ensures that fields/methods from the {@link ClassLoader} class are reachable in order to - * make native methods of the {@link Module} class work
    • + *
    • synthesizes the runtime boot module layer
    • + *
    • ensures that fields/methods from the {@link ClassLoader} class are reachable in order to make + * native methods of the {@link Module} class work
    • *
    *

    - * This feature synthesizes the runtime boot module layer by using type reachability information. - * If a type is reachable, its module is also reachable and therefore should be included in the - * runtime boot module layer. + * This feature synthesizes the runtime boot module layer by using type reachability information. If + * a type is reachable, its module is also reachable and therefore should be included in the runtime + * boot module layer. *

    *

    * The configuration for the runtime boot module layer is resolved using the module reachability @@ -73,8 +81,8 @@ * We are purposefully avoiding public API for module layer creation, such as * {@link ModuleLayer#defineModulesWithOneLoader(Configuration, ClassLoader)}, because as a side * effect this will create a new class loader. Instead, we use a private constructor to construct - * the {@link ModuleLayer} instance, which we then patch using the module reachability data - * provided to us by the analysis. + * the {@link ModuleLayer} instance, which we then patch using the module reachability data provided + * to us by the analysis. *

    *

    * Because the result of this feature is dependant on the analysis results, and because this feature @@ -86,10 +94,10 @@ @AutomaticFeature @Platforms(Platform.HOSTED_ONLY.class) public final class ModuleLayerFeature implements Feature { - - private Field moduleNameToModuleField; - private Field moduleParentsField; private Constructor moduleLayerConstructor; + private Field moduleLayerNameToModuleField; + private Field moduleLayerParentsField; + private NameToModuleSynthesizer nameToModuleSynthesizer; @Override public boolean isInConfiguration(IsInConfigurationAccess access) { @@ -99,17 +107,19 @@ public boolean isInConfiguration(IsInConfigurationAccess access) { @Override public void afterRegistration(AfterRegistrationAccess access) { ImageSingletons.add(BootModuleLayerSupport.class, new BootModuleLayerSupport()); - moduleNameToModuleField = ReflectionUtil.lookupField(ModuleLayer.class, "nameToModule"); - moduleParentsField = ReflectionUtil.lookupField(ModuleLayer.class, "parents"); moduleLayerConstructor = ReflectionUtil.lookupConstructor(ModuleLayer.class, Configuration.class, List.class, Function.class); + moduleLayerNameToModuleField = ReflectionUtil.lookupField(ModuleLayer.class, "nameToModule"); + moduleLayerParentsField = ReflectionUtil.lookupField(ModuleLayer.class, "parents"); + nameToModuleSynthesizer = new NameToModuleSynthesizer(); } @Override public void beforeAnalysis(BeforeAnalysisAccess access) { FeatureImpl.BeforeAnalysisAccessImpl accessImpl = (FeatureImpl.BeforeAnalysisAccessImpl) access; - Map baseModules = ModuleLayer.boot().modules() - .stream() - .collect(Collectors.toMap(Module::getName, m -> m)); + Set baseModules = ModuleLayer.boot().modules() + .stream() + .map(Module::getName) + .collect(Collectors.toSet()); ModuleLayer runtimeBootLayer = synthesizeRuntimeBootLayer(accessImpl.imageClassLoader, baseModules); BootModuleLayerSupport.instance().setBootLayer(runtimeBootLayer); } @@ -119,70 +129,256 @@ public void afterAnalysis(AfterAnalysisAccess access) { FeatureImpl.AfterAnalysisAccessImpl accessImpl = (FeatureImpl.AfterAnalysisAccessImpl) access; AnalysisUniverse universe = accessImpl.getUniverse(); - Map reachableModules = universe.getTypes() - .stream() - .filter(t -> t.isReachable() && !t.isArray()) - .map(t -> t.getJavaClass().getModule()) - .distinct() - .filter(m -> m.isNamed() && !m.getDescriptor().modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC)) - .collect(Collectors.toMap(Module::getName, m -> m)); + Stream analysisReachableModules = universe.getTypes() + .stream() + .filter(t -> t.isReachable() && !t.isArray()) + .map(t -> t.getJavaClass().getModule()) + .distinct(); + + Set allReachableModules = analysisReachableModules + .filter(Module::isNamed) + .filter(m -> !m.getDescriptor().modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC)) + .flatMap(ModuleLayerFeature::extractRequiredModuleNames) + .collect(Collectors.toSet()); - ModuleLayer runtimeBootLayer = synthesizeRuntimeBootLayer(accessImpl.imageClassLoader, reachableModules); + ModuleLayer runtimeBootLayer = synthesizeRuntimeBootLayer(accessImpl.imageClassLoader, allReachableModules); BootModuleLayerSupport.instance().setBootLayer(runtimeBootLayer); } - private ModuleLayer synthesizeRuntimeBootLayer(ImageClassLoader cl, Map reachableModules) { + /* + * Creates a stream of module names that are reachable from a given module through "requires" + */ + private static Stream extractRequiredModuleNames(Module m) { + Stream requiredModules = m.getDescriptor().requires().stream().map(ModuleDescriptor.Requires::name); + return Stream.concat(Stream.of(m.getName()), requiredModules); + } + + private ModuleLayer synthesizeRuntimeBootLayer(ImageClassLoader cl, Set reachableModules) { Configuration cf = synthesizeRuntimeBootLayerConfiguration(cl.modulepath(), reachableModules); try { ModuleLayer runtimeBootLayer = moduleLayerConstructor.newInstance(cf, List.of(), null); - patchRuntimeBootLayer(runtimeBootLayer, reachableModules); - // Ensure that the lazy field ModuleLayer.modules gets set - runtimeBootLayer.modules(); + Map nameToModule = nameToModuleSynthesizer.synthesizeNameToModule(runtimeBootLayer, cl.getClassLoader()); + patchRuntimeBootLayer(runtimeBootLayer, nameToModule); return runtimeBootLayer; } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) { throw VMError.shouldNotReachHere("Failed to synthesize the runtime boot module layer.", ex); } } - private Configuration synthesizeRuntimeBootLayerConfiguration(List mp, Map reachableModules) { + private static Configuration synthesizeRuntimeBootLayerConfiguration(List mp, Set reachableModules) { ModuleFinder beforeFinder = new BootModuleLayerModuleFinder(); ModuleFinder afterFinder = ModuleFinder.of(mp.toArray(Path[]::new)); - Set roots = reachableModules.keySet(); + try { - return Configuration.empty().resolve(beforeFinder, afterFinder, roots); + ModuleFinder composed = ModuleFinder.compose(beforeFinder, afterFinder); + List missingModules = new ArrayList<>(); + for (String module : reachableModules) { + Optional mref = composed.find(module); + if (mref.isEmpty()) { + missingModules.add(module); + } + } + reachableModules.removeAll(missingModules); + + return Configuration.empty().resolve(beforeFinder, afterFinder, reachableModules); } catch (FindException | ResolutionException | SecurityException ex) { throw VMError.shouldNotReachHere("Failed to synthesize the runtime boot module layer configuration.", ex); } } - private void patchRuntimeBootLayer(ModuleLayer runtimeBootLayer, Map reachableModules) { + private void patchRuntimeBootLayer(ModuleLayer runtimeBootLayer, Map nameToModule) { try { - moduleNameToModuleField.set(runtimeBootLayer, reachableModules); - moduleParentsField.set(runtimeBootLayer, List.of(ModuleLayer.empty())); + moduleLayerNameToModuleField.set(runtimeBootLayer, nameToModule); + moduleLayerParentsField.set(runtimeBootLayer, List.of(ModuleLayer.empty())); } catch (IllegalAccessException ex) { throw VMError.shouldNotReachHere("Failed to patch the runtime boot module layer.", ex); } - } + // Ensure that the lazy modules field gets set + runtimeBootLayer.modules(); + } static class BootModuleLayerModuleFinder implements ModuleFinder { @Override public Optional find(String name) { return ModuleLayer.boot() - .configuration() - .findModule(name) - .map(ResolvedModule::reference); + .configuration() + .findModule(name) + .map(ResolvedModule::reference); } @Override public Set findAll() { return ModuleLayer.boot() - .configuration() - .modules() - .stream() - .map(ResolvedModule::reference) - .collect(Collectors.toSet()); + .configuration() + .modules() + .stream() + .map(ResolvedModule::reference) + .collect(Collectors.toSet()); + } + } + + private static final class NameToModuleSynthesizer { + private final Module everyoneModule; + private final Set everyoneSet; + private final Constructor moduleConstructor; + private final Field moduleLayerField; + private final Field moduleReadsField; + private final Field moduleOpenPackagesField; + private final Field moduleExportedPackagesField; + private final Method moduleFindModuleMethod; + + NameToModuleSynthesizer() { + Method classGetDeclaredMethods0Method = ReflectionUtil.lookupMethod(Class.class, "getDeclaredFields0", boolean.class); + try { + ModuleSupport.openModuleByClass(Module.class, ModuleLayerFeature.class); + Field[] moduleClassFields = (Field[]) classGetDeclaredMethods0Method.invoke(Module.class, false); + + Field everyoneModuleField = findFieldByName(moduleClassFields, "EVERYONE_MODULE"); + everyoneModuleField.setAccessible(true); + everyoneModule = (Module) everyoneModuleField.get(null); + + moduleLayerField = findFieldByName(moduleClassFields, "layer"); + moduleReadsField = findFieldByName(moduleClassFields, "reads"); + moduleOpenPackagesField = findFieldByName(moduleClassFields, "openPackages"); + moduleExportedPackagesField = findFieldByName(moduleClassFields, "exportedPackages"); + moduleLayerField.setAccessible(true); + moduleReadsField.setAccessible(true); + moduleOpenPackagesField.setAccessible(true); + moduleExportedPackagesField.setAccessible(true); + } catch (ReflectiveOperationException | NoSuchElementException ex) { + throw VMError.shouldNotReachHere("Failed to find the value of EVERYONE_MODULE field of Module class.", ex); + } + everyoneSet = Set.of(everyoneModule); + moduleConstructor = ReflectionUtil.lookupConstructor(Module.class, ClassLoader.class, ModuleDescriptor.class); + moduleFindModuleMethod = ReflectionUtil.lookupMethod(Module.class, "findModule", String.class, Map.class, Map.class, List.class); + } + + private static Field findFieldByName(Field[] fields, String name) { + return Arrays.stream(fields).filter(f -> f.getName().equals(name)).findAny().get(); + } + + /** + * This method creates Module instances that will populate the runtime boot module layer of + * the image. This implementation is copy-pasted from Module#defineModules(Configuration, + * Function, ModuleLayer) with few simplifications (removing multiple classloader support) + * and removal of VM state updates (otherwise we would be re-defining modules to the host + * VM). + */ + Map synthesizeNameToModule(ModuleLayer runtimeBootLayer, ClassLoader cl) + throws IllegalAccessException, InvocationTargetException, InstantiationException { + Configuration cf = runtimeBootLayer.configuration(); + + int cap = (int) (cf.modules().size() / 0.75f + 1.0f); + Map nameToModule = new HashMap<>(cap); + + /* + * Remove mapping of modules to classloaders. Create module instances without defining + * them to the VM + */ + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleReference mref = resolvedModule.reference(); + ModuleDescriptor descriptor = mref.descriptor(); + String name = descriptor.name(); + Module m = moduleConstructor.newInstance(cl, descriptor); + moduleLayerField.set(m, runtimeBootLayer); + nameToModule.put(name, m); + } + + /* + * Setup readability and exports/opens. This part is unchanged, save for field setters + * and VM update removals + */ + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleReference mref = resolvedModule.reference(); + ModuleDescriptor descriptor = mref.descriptor(); + + String mn = descriptor.name(); + Module m = nameToModule.get(mn); + assert m != null; + + Set reads = new HashSet<>(); + for (ResolvedModule other : resolvedModule.reads()) { + Module m2 = nameToModule.get(other.name()); + reads.add(m2); + } + moduleReadsField.set(m, reads); + + if (!descriptor.isOpen() && !descriptor.isAutomatic()) { + if (descriptor.opens().isEmpty()) { + Map> exportedPackages = new HashMap<>(); + for (ModuleDescriptor.Exports exports : m.getDescriptor().exports()) { + String source = exports.source(); + if (exports.isQualified()) { + Set targets = new HashSet<>(); + for (String target : exports.targets()) { + Module m2 = nameToModule.get(target); + if (m2 != null) { + targets.add(m2); + } + } + if (!targets.isEmpty()) { + exportedPackages.put(source, targets); + } + } else { + exportedPackages.put(source, everyoneSet); + } + } + moduleExportedPackagesField.set(m, exportedPackages); + } else { + Map> openPackages = new HashMap<>(); + Map> exportedPackages = new HashMap<>(); + for (ModuleDescriptor.Opens opens : descriptor.opens()) { + String source = opens.source(); + if (opens.isQualified()) { + Set targets = new HashSet<>(); + for (String target : opens.targets()) { + Module m2 = (Module) moduleFindModuleMethod.invoke(null, target, Map.of(), nameToModule, runtimeBootLayer.parents()); + if (m2 != null) { + targets.add(m2); + } + } + if (!targets.isEmpty()) { + openPackages.put(source, targets); + } + } else { + openPackages.put(source, everyoneSet); + } + } + + for (ModuleDescriptor.Exports exports : descriptor.exports()) { + String source = exports.source(); + Set openToTargets = openPackages.get(source); + if (openToTargets != null && openToTargets.contains(everyoneModule)) { + continue; + } + + if (exports.isQualified()) { + Set targets = new HashSet<>(); + for (String target : exports.targets()) { + Module m2 = (Module) moduleFindModuleMethod.invoke(null, target, Map.of(), nameToModule, runtimeBootLayer.parents()); + if (m2 != null) { + if (openToTargets == null || !openToTargets.contains(m2)) { + targets.add(m2); + } + } + } + if (!targets.isEmpty()) { + exportedPackages.put(source, targets); + } + } else { + exportedPackages.put(source, everyoneSet); + } + } + + moduleOpenPackagesField.set(m, openPackages); + moduleExportedPackagesField.set(m, exportedPackages); + } + } + } + + return nameToModule; } } } diff --git a/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/jdk11/ClassLoaderSupportImplJDK11OrLater.java b/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/jdk11/ClassLoaderSupportImplJDK11OrLater.java index 3a6652ac4710..df7e017c0854 100644 --- a/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/jdk11/ClassLoaderSupportImplJDK11OrLater.java +++ b/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/jdk11/ClassLoaderSupportImplJDK11OrLater.java @@ -107,8 +107,8 @@ private static String packageName(String bundleName) { return bundleName.substring(0, classSep); } - private void buildPackageToModulesMap(NativeImageClassLoaderSupportJDK11OrLater classLoaderSupport) { - for (ModuleLayer layer : allLayers(classLoaderSupport.moduleLayerForImageBuild)) { + private void buildPackageToModulesMap(NativeImageClassLoaderSupportJDK11OrLater cls) { + for (ModuleLayer layer : allLayers(cls.moduleLayerForImageBuild)) { for (Module module : layer.modules()) { for (String packageName : module.getDescriptor().packages()) { addToPackageNameModules(module, packageName); diff --git a/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/jdk11/NativeImageClassLoaderSupportJDK11OrLater.java b/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/jdk11/NativeImageClassLoaderSupportJDK11OrLater.java index 233b351dcb04..f9c6c0b89886 100644 --- a/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/jdk11/NativeImageClassLoaderSupportJDK11OrLater.java +++ b/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/jdk11/NativeImageClassLoaderSupportJDK11OrLater.java @@ -46,6 +46,7 @@ import java.util.stream.Stream; import org.graalvm.collections.Pair; +import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; import com.oracle.svm.core.option.LocatableMultiOptionValue; @@ -54,6 +55,7 @@ import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.AbstractNativeImageClassLoaderSupport; import com.oracle.svm.hosted.ImageClassLoader; +import com.oracle.svm.hosted.NativeImageClassLoaderOptions; import com.oracle.svm.util.ModuleSupport; import jdk.internal.module.Modules; @@ -70,14 +72,13 @@ public NativeImageClassLoaderSupportJDK11OrLater(ClassLoader defaultSystemClassL super(defaultSystemClassLoader, classpath); imagemp = Arrays.stream(modulePath).map(Paths::get).collect(Collectors.toUnmodifiableList()); - buildmp = Arrays.stream(System.getProperty("jdk.module.path", "").split(File.pathSeparator)).map(Paths::get).collect(Collectors.toUnmodifiableList()); + buildmp = Optional.ofNullable(System.getProperty("jdk.module.path")).stream() + .flatMap(s -> Arrays.stream(s.split(File.pathSeparator))).map(Paths::get).collect(Collectors.toUnmodifiableList()); ModuleLayer moduleLayer = createModuleLayer(imagemp.toArray(Path[]::new), classPathClassLoader); adjustBootLayerQualifiedExports(moduleLayer); moduleLayerForImageBuild = moduleLayer; classLoader = getSingleClassloader(moduleLayer); - - adjustLibrarySupportReadAllUnnamed(); } private static ModuleLayer createModuleLayer(Path[] modulePaths, ClassLoader parent) { @@ -92,7 +93,7 @@ private static ModuleLayer createModuleLayer(Path[] modulePaths, ClassLoader par return ModuleLayer.defineModulesWithOneLoader(configuration, List.of(ModuleLayer.boot()), parent).layer(); } - private void adjustBootLayerQualifiedExports(ModuleLayer layer) { + private static void adjustBootLayerQualifiedExports(ModuleLayer layer) { /* * For all qualified exports packages of modules in the the boot layer we check if layer * contains modules that satisfy such qualified exports. If we find a match we perform a @@ -128,29 +129,14 @@ private ClassLoader getSingleClassloader(ModuleLayer moduleLayer) { return singleClassloader; } - private void adjustLibrarySupportReadAllUnnamed() { - /* - * org.graalvm.nativeimage.librarysupport depends on junit. Unfortunately using junit as - * automatic module is not possible because we have to support non-modularized tests as - * well. Thus, we have to explicitly allow org.graalvm.nativeimage.librarysupport to read - * ALL-UNNAMED so that junit from classpath is accessible to it. - * - * This workaround can be replaced with --add-reads use once GR-33504 is implemented. - */ - Optional librarySupportModule = findModule("org.graalvm.nativeimage.librarysupport"); - if (!librarySupportModule.isEmpty()) { - try { - Module moduleLibrarySupport = librarySupportModule.get(); - Method implAddReadsAllUnnamed = Module.class.getDeclaredMethod("implAddReadsAllUnnamed"); - ModuleSupport.openModuleByClass(Module.class, NativeImageClassLoaderSupportJDK11OrLater.class); - implAddReadsAllUnnamed.setAccessible(true); - implAddReadsAllUnnamed.invoke(moduleLibrarySupport); - } catch (ReflectiveOperationException | NoSuchElementException e) { - VMError.shouldNotReachHere("Could not adjust org.graalvm.nativeimage.librarysupport to read all unnamed modules", e); - } - } else { - VMError.guarantee(!org.graalvm.compiler.options.ModuleSupport.USE_NI_JPMS, - "Image-builder on module-path requires module org.graalvm.nativeimage.librarysupport"); + private static void implAddReadsAllUnnamed(Module module) { + try { + Method implAddReadsAllUnnamed = Module.class.getDeclaredMethod("implAddReadsAllUnnamed"); + ModuleSupport.openModuleByClass(Module.class, NativeImageClassLoaderSupportJDK11OrLater.class); + implAddReadsAllUnnamed.setAccessible(true); + implAddReadsAllUnnamed.invoke(module); + } catch (ReflectiveOperationException | NoSuchElementException e) { + VMError.shouldNotReachHere("Could reflectively call Module.implAddReadsAllUnnamed", e); } } @@ -170,9 +156,8 @@ protected Optional findModule(String moduleName) { } @Override - protected void processAddExportsAndAddOpens(OptionValues parsedHostedOptions) { - LocatableMultiOptionValue.Strings addExports = NativeImageClassLoaderOptions.AddExports.getValue(parsedHostedOptions); - addExports.getValuesWithOrigins().map(this::asAddExportsAndOpensFormatValue).forEach(val -> { + protected void processClassLoaderOptions(OptionValues optionValues) { + processOption(optionValues, NativeImageClassLoaderOptions.AddExports).forEach(val -> { if (val.targetModules.isEmpty()) { Modules.addExportsToAllUnnamed(val.module, val.packageName); } else { @@ -181,8 +166,7 @@ protected void processAddExportsAndAddOpens(OptionValues parsedHostedOptions) { } } }); - LocatableMultiOptionValue.Strings addOpens = NativeImageClassLoaderOptions.AddOpens.getValue(parsedHostedOptions); - addOpens.getValuesWithOrigins().map(this::asAddExportsAndOpensFormatValue).forEach(val -> { + processOption(optionValues, NativeImageClassLoaderOptions.AddOpens).forEach(val -> { if (val.targetModules.isEmpty()) { Modules.addOpensToAllUnnamed(val.module, val.packageName); } else { @@ -191,47 +175,80 @@ protected void processAddExportsAndAddOpens(OptionValues parsedHostedOptions) { } } }); + processOption(optionValues, NativeImageClassLoaderOptions.AddReads).forEach(val -> { + if (val.targetModules.isEmpty()) { + implAddReadsAllUnnamed(val.module); + } else { + for (Module targetModule : val.targetModules) { + Modules.addReads(val.module, targetModule); + } + } + }); + } + + private Stream processOption(OptionValues parsedHostedOptions, OptionKey specificOption) { + Stream> valuesWithOrigins = specificOption.getValue(parsedHostedOptions).getValuesWithOrigins(); + Stream parsedOptions = valuesWithOrigins.flatMap(valWithOrig -> { + try { + return Stream.of(asAddExportsAndOpensAndReadsFormatValue(specificOption, valWithOrig)); + } catch (UserError.UserException e) { + if (ModuleSupport.modulePathBuild) { + throw e; + } else { + /* + * Until we switch to always running the image-builder on module-path we have to + * be tolerant if invalid --add-exports -add-opens or --add-reads options are + * used. GR-30433 + */ + System.out.println("Warning: " + e.getMessage()); + return Stream.empty(); + } + } + }); + return parsedOptions; } - private static final class AddExportsAndOpensFormatValue { + private static final class AddExportsAndOpensAndReadsFormatValue { private final Module module; private final String packageName; private final List targetModules; - private AddExportsAndOpensFormatValue(Module module, String packageName, List targetModules) { + private AddExportsAndOpensAndReadsFormatValue(Module module, String packageName, List targetModules) { this.module = module; this.packageName = packageName; this.targetModules = targetModules; } } - private AddExportsAndOpensFormatValue asAddExportsAndOpensFormatValue(Pair valueOrigin) { + private AddExportsAndOpensAndReadsFormatValue asAddExportsAndOpensAndReadsFormatValue(OptionKey option, Pair valueOrigin) { String optionOrigin = valueOrigin.getRight(); String optionValue = valueOrigin.getLeft(); - String syntaxErrorMessage = " Allowed value format: " + NativeImageClassLoaderOptions.AddExportsAndOpensFormat; + boolean reads = option.equals(NativeImageClassLoaderOptions.AddReads); + String format = reads ? NativeImageClassLoaderOptions.AddReadsFormat : NativeImageClassLoaderOptions.AddExportsAndOpensFormat; + String syntaxErrorMessage = " Allowed value format: " + format; String[] modulePackageAndTargetModules = optionValue.split("=", 2); if (modulePackageAndTargetModules.length != 2) { - throw userErrorAddExportsAndOpens(optionOrigin, optionValue, syntaxErrorMessage); + throw userErrorAddExportsAndOpensAndReads(option, optionOrigin, optionValue, syntaxErrorMessage); } String modulePackage = modulePackageAndTargetModules[0]; String targetModuleNames = modulePackageAndTargetModules[1]; String[] moduleAndPackage = modulePackage.split("/"); - if (moduleAndPackage.length != 2) { - throw userErrorAddExportsAndOpens(optionOrigin, optionValue, syntaxErrorMessage); + if (moduleAndPackage.length > 1 + (reads ? 0 : 1)) { + throw userErrorAddExportsAndOpensAndReads(option, optionOrigin, optionValue, syntaxErrorMessage); } String moduleName = moduleAndPackage[0]; - String packageName = moduleAndPackage[1]; + String packageName = moduleAndPackage.length > 1 ? moduleAndPackage[1] : null; List targetModuleNamesList = Arrays.asList(targetModuleNames.split(",")); if (targetModuleNamesList.isEmpty()) { - throw userErrorAddExportsAndOpens(optionOrigin, optionValue, syntaxErrorMessage); + throw userErrorAddExportsAndOpensAndReads(option, optionOrigin, optionValue, syntaxErrorMessage); } Module module = findModule(moduleName).orElseThrow(() -> { - return userErrorAddExportsAndOpens(optionOrigin, optionValue, " Specified module '" + moduleName + "' is unknown."); + return userErrorAddExportsAndOpensAndReads(option, optionOrigin, optionValue, " Specified module '" + moduleName + "' is unknown."); }); List targetModules; if (targetModuleNamesList.contains("ALL-UNNAMED")) { @@ -239,16 +256,16 @@ private AddExportsAndOpensFormatValue asAddExportsAndOpensFormatValue(Pair { return findModule(mn).orElseThrow(() -> { - throw userErrorAddExportsAndOpens(optionOrigin, optionValue, " Specified target-module '" + mn + "' is unknown."); + throw userErrorAddExportsAndOpensAndReads(option, optionOrigin, optionValue, " Specified target-module '" + mn + "' is unknown."); }); }).collect(Collectors.toList()); } - return new AddExportsAndOpensFormatValue(module, packageName, targetModules); + return new AddExportsAndOpensAndReadsFormatValue(module, packageName, targetModules); } - private static UserError.UserException userErrorAddExportsAndOpens(String origin, String value, String detailMessage) { + private static UserError.UserException userErrorAddExportsAndOpensAndReads(OptionKey option, String origin, String value, String detailMessage) { Objects.requireNonNull(detailMessage, "missing detailMessage"); - return UserError.abort("Invalid option %s provided by %s." + detailMessage, SubstrateOptionsParser.commandArgument(NativeImageClassLoaderOptions.AddExports, value), origin); + return UserError.abort("Invalid option %s provided by %s." + detailMessage, SubstrateOptionsParser.commandArgument(option, value), origin); } @Override diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/localization/LocalizationFeatureJDK11OrLater.java b/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/jdk11/localization/LocalizationFeatureJDK11OrLater.java similarity index 95% rename from substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/localization/LocalizationFeatureJDK11OrLater.java rename to substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/jdk11/localization/LocalizationFeatureJDK11OrLater.java index a61cd2cff607..82b5f01b8582 100644 --- a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/localization/LocalizationFeatureJDK11OrLater.java +++ b/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/jdk11/localization/LocalizationFeatureJDK11OrLater.java @@ -23,7 +23,7 @@ * questions. */ -package com.oracle.svm.core.jdk11.localization; +package com.oracle.svm.hosted.jdk11.localization; import java.util.ArrayList; import java.util.Collections; @@ -34,7 +34,7 @@ import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import com.oracle.svm.core.annotate.AutomaticFeature; -import com.oracle.svm.core.jdk.localization.LocalizationFeature; +import com.oracle.svm.hosted.jdk.localization.LocalizationFeature; //Checkstyle: stop import sun.text.spi.JavaTimeDateTimePatternProvider; diff --git a/substratevm/src/com.oracle.svm.hosted.jdk14/src/com/oracle/svm/hosted/jdk/JNIRegistrationSupport_JDK14OrLater.java b/substratevm/src/com.oracle.svm.hosted.jdk17/src/com/oracle/svm/hosted/jdk17/JNIRegistrationSupport_JDK17OrLater.java similarity index 82% rename from substratevm/src/com.oracle.svm.hosted.jdk14/src/com/oracle/svm/hosted/jdk/JNIRegistrationSupport_JDK14OrLater.java rename to substratevm/src/com.oracle.svm.hosted.jdk17/src/com/oracle/svm/hosted/jdk17/JNIRegistrationSupport_JDK17OrLater.java index bf3572c0cfc5..05db2050e164 100644 --- a/substratevm/src/com.oracle.svm.hosted.jdk14/src/com/oracle/svm/hosted/jdk/JNIRegistrationSupport_JDK14OrLater.java +++ b/substratevm/src/com.oracle.svm.hosted.jdk17/src/com/oracle/svm/hosted/jdk17/JNIRegistrationSupport_JDK17OrLater.java @@ -22,26 +22,33 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.hosted.jdk; +package com.oracle.svm.hosted.jdk17; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; import org.graalvm.compiler.phases.util.Providers; +import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.impl.InternalPlatform; import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.core.graal.GraalFeature; +import com.oracle.svm.hosted.jdk.JNIRegistrationSupport; import jdk.internal.loader.BootLoader; /** - * Registration of native JDK libraries for JDK 14 and later that are loaded via + * Registration of native JDK libraries for JDK 17 and later that are loaded via * jdk.internal.loader.BootLoader */ @Platforms(InternalPlatform.PLATFORM_JNI.class) @AutomaticFeature -class JNIRegistrationSupport_JDK14OrLater implements GraalFeature { +final class JNIRegistrationSupport_JDK17OrLater implements GraalFeature { + @Override + public boolean isInConfiguration(IsInConfigurationAccess access) { + return JavaVersionUtil.JAVA_SPEC >= 17; + } + @Override public void registerGraphBuilderPlugins(Providers providers, Plugins plugins, ParsingReason reason) { JNIRegistrationSupport.singleton().registerLoadLibraryPlugin(plugins, BootLoader.class); diff --git a/substratevm/src/com.oracle.svm.core.jdk8/src/com/oracle/svm/core/jdk8/LocalizationFeatureJDK8.java b/substratevm/src/com.oracle.svm.hosted.jdk8/src/com/oracle/svm/hosted/jdk8/LocalizationFeatureJDK8.java similarity index 93% rename from substratevm/src/com.oracle.svm.core.jdk8/src/com/oracle/svm/core/jdk8/LocalizationFeatureJDK8.java rename to substratevm/src/com.oracle.svm.hosted.jdk8/src/com/oracle/svm/hosted/jdk8/LocalizationFeatureJDK8.java index b5645bbb0204..b242c230d693 100644 --- a/substratevm/src/com.oracle.svm.core.jdk8/src/com/oracle/svm/core/jdk8/LocalizationFeatureJDK8.java +++ b/substratevm/src/com.oracle.svm.hosted.jdk8/src/com/oracle/svm/hosted/jdk8/LocalizationFeatureJDK8.java @@ -23,12 +23,12 @@ * questions. */ -package com.oracle.svm.core.jdk8; +package com.oracle.svm.hosted.jdk8; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import com.oracle.svm.core.annotate.AutomaticFeature; -import com.oracle.svm.core.jdk.localization.LocalizationFeature; +import com.oracle.svm.hosted.jdk.localization.LocalizationFeature; @AutomaticFeature final class LocalizationFeatureJDK8 extends LocalizationFeature { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/AbstractNativeImageClassLoaderSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/AbstractNativeImageClassLoaderSupport.java index 38e429d4abac..37c0e461fbf5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/AbstractNativeImageClassLoaderSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/AbstractNativeImageClassLoaderSupport.java @@ -62,6 +62,7 @@ import com.oracle.svm.core.util.InterruptImageBuilding; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.option.HostedOptionParser; public abstract class AbstractNativeImageClassLoaderSupport { @@ -109,7 +110,30 @@ public ClassLoader getClassLoader() { protected abstract Optional findModule(String moduleName); - protected abstract void processAddExportsAndAddOpens(OptionValues parsedHostedOptions); + private HostedOptionParser hostedOptionParser; + private OptionValues parsedHostedOptions; + private List remainingArguments; + + public void setupHostedOptionParser(List arguments) { + hostedOptionParser = new HostedOptionParser(getClassLoader()); + remainingArguments = Collections.unmodifiableList((hostedOptionParser.parse(arguments))); + parsedHostedOptions = new OptionValues(hostedOptionParser.getHostedValues()); + processClassLoaderOptions(parsedHostedOptions); + } + + public HostedOptionParser getHostedOptionParser() { + return hostedOptionParser; + } + + public List getRemainingArguments() { + return remainingArguments; + } + + public OptionValues getParsedHostedOptions() { + return parsedHostedOptions; + } + + protected abstract void processClassLoaderOptions(OptionValues optionValues); protected abstract void initAllClasses(ForkJoinPool executor, ImageClassLoader imageClassLoader); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java index f1bf9e8e0ad8..f2ca7753b5c2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java @@ -35,6 +35,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Deque; +import java.util.HashSet; import java.util.IdentityHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -227,11 +228,11 @@ public boolean isReachable(AnalysisMethod method) { public Set> reachableSubtypes(Class baseClass) { return reachableSubtypes(getMetaAccess().lookupJavaType(baseClass)).stream() - .map(AnalysisType::getJavaClass).collect(Collectors.toCollection(LinkedHashSet::new)); + .map(AnalysisType::getJavaClass).collect(Collectors.toCollection(HashSet::new)); } Set reachableSubtypes(AnalysisType baseType) { - Set result = AnalysisUniverse.getSubtypes(baseType); + Set result = AnalysisUniverse.getAllSubtypes(baseType); result.removeIf(t -> !isReachable(t)); return result; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java index d4d8a5a844e9..4e7930ba7365 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java @@ -31,16 +31,15 @@ import java.util.Set; import java.util.concurrent.ForkJoinPool; -import com.oracle.graal.pointsto.BigBang; -import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.analysis.Inflation; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.core.common.CompressEncoding; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.options.OptionValues; import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.flow.MethodTypeFlow; import com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder; @@ -54,6 +53,8 @@ import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.config.ObjectLayout; import com.oracle.svm.core.monitor.MultiThreadedMonitorSupport; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.analysis.Inflation; import com.oracle.svm.hosted.analysis.flow.SVMMethodTypeFlowBuilder; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.code.CompileQueue; @@ -67,7 +68,6 @@ import com.oracle.svm.hosted.substitute.UnsafeAutomaticSubstitutionProcessor; import jdk.vm.ci.meta.JavaKind; -import org.graalvm.nativeimage.Platform; public class HostedConfiguration { @@ -132,9 +132,9 @@ public static ObjectLayout createObjectLayout(JavaKind referenceKind) { return new ObjectLayout(target, referenceSize, objectAlignment, hubOffset, firstFieldOffset, arrayLengthOffset, arrayBaseOffset, identityHashCodeOffset); } - public SVMHost createHostVM(OptionValues options, ForkJoinPool buildExecutor, ClassLoader classLoader, ClassInitializationSupport classInitializationSupport, + public SVMHost createHostVM(OptionValues options, ClassLoader classLoader, ClassInitializationSupport classInitializationSupport, UnsafeAutomaticSubstitutionProcessor automaticSubstitutions, Platform platform) { - return new SVMHost(options, buildExecutor, classLoader, classInitializationSupport, automaticSubstitutions, platform); + return new SVMHost(options, classLoader, classInitializationSupport, automaticSubstitutions, platform); } public CompileQueue createCompileQueue(DebugContext debug, FeatureHandler featureHandler, HostedUniverse hostedUniverse, @@ -207,7 +207,7 @@ private static Set getForceMonitorSlotTypes(BigBang bb) { /** Process the types that the analysis found as needing synchronization. */ protected void processedSynchronizedTypes(BigBang bb, HostedUniverse hUniverse, Set immutableTypes) { TypeState allSynchronizedTypeState = bb.getAllSynchronizedTypeState(); - for (AnalysisType type : allSynchronizedTypeState.types()) { + for (AnalysisType type : allSynchronizedTypeState.types(bb)) { maybeSetMonitorField(hUniverse, immutableTypes, type); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageClassLoader.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageClassLoader.java index be8f57d91714..7ab7aa98bd6c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageClassLoader.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageClassLoader.java @@ -44,7 +44,6 @@ import java.util.stream.StreamSupport; import org.graalvm.collections.EconomicSet; -import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -427,8 +426,4 @@ public Optional getMainClassFromModule(Object module) { public Optional findModule(String moduleName) { return classLoaderSupport.findModule(moduleName); } - - public void processAddExportsAndAddOpens(OptionValues parsedHostedOptions) { - classLoaderSupport.processAddExportsAndAddOpens(parsedHostedOptions); - } } diff --git a/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/jdk11/NativeImageClassLoaderOptions.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderOptions.java similarity index 77% rename from substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/jdk11/NativeImageClassLoaderOptions.java rename to substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderOptions.java index 36847454afe9..58fa54f1cde3 100644 --- a/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/jdk11/NativeImageClassLoaderOptions.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderOptions.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.hosted.jdk11; +package com.oracle.svm.hosted; import org.graalvm.compiler.options.Option; @@ -31,7 +31,8 @@ import com.oracle.svm.core.option.LocatableMultiOptionValue; public class NativeImageClassLoaderOptions { - static final String AddExportsAndOpensFormat = "/=(,)*"; + public static final String AddExportsAndOpensFormat = "/=(,)*"; + public static final String AddReadsFormat = "=(,)*"; @APIOption(name = "add-exports", extra = true)// @Option(help = "Value " + AddExportsAndOpensFormat + " updates to export to , regardless of module declaration." + @@ -41,4 +42,9 @@ public class NativeImageClassLoaderOptions { @APIOption(name = "add-opens", extra = true)// @Option(help = "Value " + AddExportsAndOpensFormat + " updates to open to , regardless of module declaration.")// public static final HostedOptionKey AddOpens = new HostedOptionKey<>(new LocatableMultiOptionValue.Strings()); + + @APIOption(name = "add-reads", extra = true)// + @Option(help = "Value " + AddReadsFormat + " updates to read , regardless of module declaration." + + " can be ALL-UNNAMED to read all unnamed modules.")// + public static final HostedOptionKey AddReads = new HostedOptionKey<>(new LocatableMultiOptionValue.Strings()); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java index 8ac65f886623..a21f19a7e8b2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java @@ -54,7 +54,7 @@ protected Optional findModule(String moduleName) { } @Override - protected void processAddExportsAndAddOpens(OptionValues parsedHostedOptions) { + protected void processClassLoaderOptions(OptionValues optionValues) { /* Nothing to do for Java 8 */ } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index e6df8a8d4b78..3429c20048ec 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -55,9 +55,11 @@ import java.util.Set; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.BooleanSupplier; import java.util.function.Consumer; import java.util.stream.Collectors; +import com.oracle.svm.hosted.image.sources.SourceManager; import org.graalvm.collections.EconomicSet; import org.graalvm.collections.Pair; import org.graalvm.compiler.api.replacements.Fold; @@ -149,10 +151,13 @@ import com.oracle.graal.pointsto.reports.AnalysisReporter; import com.oracle.graal.pointsto.reports.ReportUtils; import com.oracle.graal.pointsto.typestate.TypeState; +import com.oracle.graal.pointsto.util.AnalysisError; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.graal.pointsto.util.Timer; import com.oracle.graal.pointsto.util.Timer.StopTimer; import com.oracle.svm.core.BuildArtifacts; import com.oracle.svm.core.BuildArtifacts.ArtifactType; +import com.oracle.svm.core.BuildPhaseProvider; import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.JavaMainWrapper.JavaMainSupport; import com.oracle.svm.core.LinkerInvocation; @@ -192,13 +197,14 @@ import com.oracle.svm.core.graal.snippets.ExceptionSnippets; import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; import com.oracle.svm.core.graal.snippets.TypeSnippets; +import com.oracle.svm.core.graal.word.SubstrateWordOperationPlugins; import com.oracle.svm.core.graal.word.SubstrateWordTypes; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.RestrictHeapAccessCallees; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.hub.LayoutEncoding; import com.oracle.svm.core.image.ImageHeapLayouter; -import com.oracle.svm.core.jdk.localization.LocalizationFeature; +import com.oracle.svm.hosted.jdk.localization.LocalizationFeature; import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.core.option.OptionUtils; import com.oracle.svm.core.option.RuntimeOptionValues; @@ -223,10 +229,10 @@ import com.oracle.svm.hosted.analysis.Inflation; import com.oracle.svm.hosted.analysis.NativeImagePointsToAnalysis; import com.oracle.svm.hosted.analysis.SVMAnalysisMetaAccess; +import com.oracle.svm.hosted.analysis.SubstrateUnsupportedFeatures; import com.oracle.svm.hosted.annotation.AnnotationSupport; import com.oracle.svm.hosted.c.CAnnotationProcessorCache; import com.oracle.svm.hosted.c.CConstantValueSupportImpl; -import com.oracle.svm.hosted.c.GraalAccess; import com.oracle.svm.hosted.c.NativeLibraries; import com.oracle.svm.hosted.c.OffsetOfSupportImpl; import com.oracle.svm.hosted.c.SizeOfSupportImpl; @@ -544,6 +550,7 @@ private void doRun(Map entryPoints, new UniverseBuilder(aUniverse, bb.getMetaAccess(), hUniverse, hMetaAccess, HostedConfiguration.instance().createStaticAnalysisResultsBuilder(bb, hUniverse), bb.getUnsupportedFeatures()).build(debug); + BuildPhaseProvider.markHostedUniverseBuilt(); ClassInitializationSupport classInitializationSupport = bb.getHostVM().getClassInitializationSupport(); runtime = new HostedRuntimeConfigurationBuilder(options, bb.getHostVM(), hUniverse, hMetaAccess, bb.getProviders(), nativeLibraries, classInitializationSupport, GraalAccess.getOriginalProviders().getLoopsDataProvider()).build(); @@ -591,10 +598,12 @@ private void doRun(Map entryPoints, featureHandler.forEachFeature(feature -> feature.beforeCompilation(beforeCompilationConfig)); runtime.updateLazyState(hMetaAccess); + ImageSingletons.add(SourceManager.class, new SourceManager()); NativeImageCodeCache codeCache; CompileQueue compileQueue; try (StopTimer t = new Timer(imageName, "compile").start()) { + //ImageSingletons.add(SourceManager.class, new SourceManager()); compileQueue = HostedConfiguration.instance().createCompileQueue(debug, featureHandler, hUniverse, runtime, DeoptTester.enabled(), bb.getProviders().getSnippetReflection(), compilationExecutor); compileQueue.finish(debug); @@ -690,51 +699,15 @@ private boolean runPointsToAnalysis(String imageName, OptionValues options, Debu } try (StopTimer t = bb.getAnalysisTimer().start()) { - - /* - * Iterate until analysis reaches a fixpoint. - */ DuringAnalysisAccessImpl config = new DuringAnalysisAccessImpl(featureHandler, loader, bb, nativeLibraries, debug); - int numIterations = 0; - while (true) { - try (Indent indent2 = debug.logAndIndent("new analysis iteration")) { - /* - * Do the analysis (which itself is done in a similar iterative process) - */ - boolean analysisChanged = bb.finish(); - - numIterations++; - if (numIterations > 1000) { - /* - * Usually there are < 10 iterations. If we have so many iterations, we - * probably have an endless loop (but at least we have a performance - * problem because we re-start the analysis so often). - */ - throw UserError.abort("Static analysis did not reach a fix point after %d iterations because a Feature keeps requesting new analysis iterations. " + - "The analysis itself %s find a change in type states in the last iteration.", - numIterations, analysisChanged ? "DID" : "DID NOT"); - } - - /* - * Allow features to change the universe. - */ - try (StopTimer t2 = bb.getProcessFeaturesTimer().start()) { - int numTypes = aUniverse.getTypes().size(); - int numMethods = aUniverse.getMethods().size(); - int numFields = aUniverse.getFields().size(); - - bb.getHostVM().notifyClassReachabilityListener(aUniverse, config); - featureHandler.forEachFeature(feature -> feature.duringAnalysis(config)); - - if (!config.getAndResetRequireAnalysisIteration()) { - if (numTypes != aUniverse.getTypes().size() || numMethods != aUniverse.getMethods().size() || numFields != aUniverse.getFields().size()) { - throw UserError.abort( - "When a feature makes more types, methods, or fields reachable, it must require another analysis iteration via DuringAnalysisAccess.requireAnalysisIteration()"); - } - break; - } - } - } + try { + bb.runAnalysis(debug, (universe) -> { + bb.getHostVM().notifyClassReachabilityListener(universe, config); + featureHandler.forEachFeature(feature -> feature.duringAnalysis(config)); + return !config.getAndResetRequireAnalysisIteration(); + }); + } catch (AnalysisError e) { + throw UserError.abort(e, "Analysis step failed. Reason: %s.", e.getMessage()); } assert verifyAssignableTypes(imageName); @@ -745,6 +718,7 @@ private boolean runPointsToAnalysis(String imageName, OptionValues options, Debu */ nativeLibraries.processAnnotated(); + BuildPhaseProvider.markAnalysisFinished(); AfterAnalysisAccessImpl postConfig = new AfterAnalysisAccessImpl(featureHandler, loader, bb, debug); featureHandler.forEachFeature(feature -> feature.afterAnalysis(postConfig)); @@ -820,6 +794,9 @@ private void setupNativeImage(String imageName, OptionValues options, Map feature.afterRegistration(access)); @@ -839,9 +816,12 @@ private void setupNativeImage(String imageName, OptionValues options, Map additionalSubstitutions, ForkJoinPool buildExecutor) { + ClassInitializationSupport classInitializationSupport, List additionalSubstitutions) { UnsafeAutomaticSubstitutionProcessor automaticSubstitutions = createAutomaticUnsafeSubstitutions(originalSnippetReflection, annotationSubstitutions); SubstitutionProcessor aSubstitutions = createAnalysisSubstitutionProcessor(originalMetaAccess, originalSnippetReflection, cEnumProcessor, automaticSubstitutions, annotationSubstitutions, additionalSubstitutions); - SVMHost hostVM = HostedConfiguration.instance().createHostVM(options, buildExecutor, loader.getClassLoader(), classInitializationSupport, automaticSubstitutions, loader.platform); + SVMHost hostVM = HostedConfiguration.instance().createHostVM(options, loader.getClassLoader(), classInitializationSupport, automaticSubstitutions, loader.platform); automaticSubstitutions.init(loader, originalMetaAccess); AnalysisPolicy analysisPolicy = PointstoOptions.AllocationSiteSensitiveHeap.getValue(options) ? new BytecodeSensitiveAnalysisPolicy(options) @@ -1030,7 +1010,7 @@ public static Inflation createBigBang(OptionValues options, TargetDescription ta aProviders = new HostedProviders(aMetaAccess, null, aConstantReflection, aConstantFieldProvider, aForeignCalls, aLoweringProvider, aReplacments, aStampProvider, aSnippetReflection, aWordTypes, platformConfig, aMetaAccessExtensionProvider, originalProviders.getLoopsDataProvider()); - return new NativeImagePointsToAnalysis(options, aUniverse, aProviders, annotationSubstitutionProcessor, analysisExecutor, heartbeatCallback); + return new NativeImagePointsToAnalysis(options, aUniverse, aProviders, annotationSubstitutionProcessor, analysisExecutor, heartbeatCallback, new SubstrateUnsupportedFeatures()); } @SuppressWarnings("try") @@ -1058,16 +1038,26 @@ private NativeLibraries setupNativeLibraries(String imageName, ConstantReflectio } } + @SuppressWarnings("deprecation") private void registerEntryPoints(Map entryPoints) { for (Method m : loader.findAnnotatedMethods(CEntryPoint.class)) { if (!Modifier.isStatic(m.getModifiers())) { throw UserError.abort("Entry point method %s.%s is not static. Add a static modifier to the method.", m.getDeclaringClass().getName(), m.getName()); } - boolean include = true; + Class cEntryPointIncludeClass = m.getAnnotation(CEntryPoint.class).include(); + boolean include = ReflectionUtil.newInstance(cEntryPointIncludeClass).getAsBoolean(); CEntryPointOptions options = m.getAnnotation(CEntryPointOptions.class); if (options != null) { - include = ReflectionUtil.newInstance(options.include()).getAsBoolean(); + Class cEntryPointOptionsIncludeClass = options.include(); + if (cEntryPointOptionsIncludeClass != CEntryPointOptions.AlwaysIncluded.class) { + if (cEntryPointIncludeClass != CEntryPoint.AlwaysIncluded.class) { + throw UserError.abort( + "The 'include' attribute for entry point method %s.%s is specified both in 'CEntryPoint' and 'CEntryPointOptions' annotations. Remove the deprecated 'CEntryPointOptions#include' attribute.", + m.getDeclaringClass().getName(), m.getName()); + } + include = ReflectionUtil.newInstance(cEntryPointOptionsIncludeClass).getAsBoolean(); + } } if (include) { entryPoints.put(m, CEntryPointData.create(m)); @@ -1109,7 +1099,7 @@ public static void registerGraphBuilderPlugins(FeatureHandler featureHandler, Ru TargetDescription target) { GraphBuilderConfiguration.Plugins plugins = new GraphBuilderConfiguration.Plugins(new SubstitutionInvocationPlugins(annotationSubstitutionProcessor)); - WordOperationPlugin wordOperationPlugin = new WordOperationPlugin(providers.getSnippetReflection(), providers.getWordTypes()); + WordOperationPlugin wordOperationPlugin = new SubstrateWordOperationPlugins(providers.getSnippetReflection(), providers.getWordTypes()); SubstrateReplacements replacements = (SubstrateReplacements) providers.getReplacements(); plugins.appendInlineInvokePlugin(replacements); @@ -1403,8 +1393,8 @@ private static boolean addAssertionLIRPhases(LIRSuites lirSuites, boolean hosted return true; } - private static String format(TypeState state) { - return state.typesStream().map(t -> t.toJavaName(true)).collect(Collectors.joining(",")); + private static String format(BigBang bb, TypeState state) { + return state.typesStream(bb).map(t -> t.toJavaName(true)).collect(Collectors.joining(",")); } private void checkUniverse() { @@ -1430,8 +1420,8 @@ private void checkUniverse() { String methodKey = method.format("%H.%n(%p)"); bigbang.getUnsupportedFeatures().addMessage(methodKey, method, "Parameter " + i + " of " + methodKey + " has declared type " + declaredType.toJavaName(true) + - ", with assignable types: " + format(declaredTypeState) + - ", which is incompatible with analysis inferred types: " + format(parameterState) + "."); + ", with assignable types: " + format(bb, declaredTypeState) + + ", which is incompatible with analysis inferred types: " + format(bb, parameterState) + "."); } } } @@ -1448,8 +1438,8 @@ private void checkUniverse() { String fieldKey = field.format("%H.%n"); bigbang.getUnsupportedFeatures().addMessage(fieldKey, null, "Field " + fieldKey + " has declared type " + declaredType.toJavaName(true) + - ", with assignable types: " + format(declaredTypeState) + - ", which is incompatible with analysis inferred types: " + format(state) + "."); + ", with assignable types: " + format(bb, declaredTypeState) + + ", which is incompatible with analysis inferred types: " + format(bb, state) + "."); } } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java index 6c50c57e7ae6..c66c8b2482bc 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java @@ -53,6 +53,7 @@ import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.graal.pointsto.util.AnalysisError.ParsingError; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.graal.pointsto.util.ParallelExecutionException; import com.oracle.graal.pointsto.util.Timer; import com.oracle.graal.pointsto.util.Timer.StopTimer; @@ -67,7 +68,6 @@ import com.oracle.svm.core.util.UserError.UserException; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.analysis.NativeImagePointsToAnalysis; -import com.oracle.svm.hosted.c.GraalAccess; import com.oracle.svm.hosted.code.CEntryPointData; import com.oracle.svm.hosted.image.AbstractImage.NativeImageKind; import com.oracle.svm.hosted.option.HostedOptionParser; @@ -118,8 +118,28 @@ public void run() { int exitStatus; ClassLoader applicationClassLoader = Thread.currentThread().getContextClassLoader(); try { - ImageClassLoader imageClassLoader = installNativeImageClassLoader(classPath, modulePath); - exitStatus = new NativeImageGeneratorRunner().build(arguments.toArray(new String[0]), imageClassLoader); + ImageClassLoader imageClassLoader = installNativeImageClassLoader(classPath, modulePath, arguments); + List remainingArguments = imageClassLoader.classLoaderSupport.getRemainingArguments(); + if (!remainingArguments.isEmpty()) { + throw UserError.abort("Unknown options: %s", String.join(" ", remainingArguments)); + } + exitStatus = new NativeImageGeneratorRunner().build(imageClassLoader); + } catch (UserException e) { + reportUserError(e.getMessage()); + exitStatus = 1; + } catch (InterruptImageBuilding e) { + if (e.getReason().isPresent()) { + if (!e.getReason().get().isEmpty()) { + NativeImageGeneratorRunner.info(e.getReason().get()); + } + exitStatus = 0; + } else { + /* InterruptImageBuilding without explicit reason is exit code 3 */ + exitStatus = 3; + } + } catch (Throwable err) { + reportFatalError(err); + exitStatus = 1; } finally { uninstallNativeImageClassLoader(); Thread.currentThread().setContextClassLoader(applicationClassLoader); @@ -149,12 +169,14 @@ public static void uninstallNativeImageClassLoader() { * * @param classpath for the application and image should be built for. * @param modulepath for the application and image should be built for (only for Java >= 11). + * @param arguments * @return NativeImageClassLoaderSupport that exposes the {@code ClassLoader} for image building * via {@link NativeImageClassLoaderSupport#getClassLoader()}. */ - public static ImageClassLoader installNativeImageClassLoader(String[] classpath, String[] modulepath) { + public static ImageClassLoader installNativeImageClassLoader(String[] classpath, String[] modulepath, List arguments) { NativeImageSystemClassLoader nativeImageSystemClassLoader = NativeImageSystemClassLoader.singleton(); AbstractNativeImageClassLoaderSupport nativeImageClassLoaderSupport = createNativeImageClassLoaderSupport(nativeImageSystemClassLoader.defaultSystemClassLoader, classpath, modulepath); + nativeImageClassLoaderSupport.setupHostedOptionParser(arguments); ClassLoader nativeImageClassLoader = nativeImageClassLoaderSupport.getClassLoader(); Thread.currentThread().setContextClassLoader(nativeImageClassLoader); /* @@ -259,32 +281,24 @@ private static boolean isValidOperatingSystem() { } @SuppressWarnings("try") - private int buildImage(String[] arguments, ImageClassLoader classLoader) { + private int buildImage(ImageClassLoader classLoader) { if (!verifyValidJavaVersionAndPlatform()) { return 1; } String imageName = null; Timer totalTimer = new Timer("[total]", false); + + HostedOptionParser optionParser = classLoader.classLoaderSupport.getHostedOptionParser(); + OptionValues parsedHostedOptions = classLoader.classLoaderSupport.getParsedHostedOptions(); + ForkJoinPool analysisExecutor = null; ForkJoinPool compilationExecutor = null; - OptionValues parsedHostedOptions = null; try (StopTimer ignored = totalTimer.start()) { Timer classlistTimer = new Timer("classlist", false); try (StopTimer ignored1 = classlistTimer.start()) { classLoader.initAllClasses(); } - HostedOptionParser optionParser = new HostedOptionParser(classLoader); - String[] remainingArgs = optionParser.parse(arguments); - if (remainingArgs.length > 0) { - throw UserError.abort("Unknown options: %s", Arrays.toString(remainingArgs)); - } - - /* - * We do not have the VMConfiguration and the HostedOptionValues set up yet, so we need - * to pass the OptionValues explicitly when accessing options. - */ - parsedHostedOptions = new OptionValues(optionParser.getHostedValues()); DebugContext debug = new DebugContext.Builder(parsedHostedOptions, new GraalDebugHandlersFactory(GraalAccess.getOriginalSnippetReflection())).build(); imageName = SubstrateOptions.Name.getValue(parsedHostedOptions); @@ -323,8 +337,6 @@ private int buildImage(String[] arguments, ImageClassLoader classLoader) { SubstrateOptionsParser.commandArgument(SubstrateOptions.Class, "")); } - classLoader.processAddExportsAndAddOpens(parsedHostedOptions); - if (!className.isEmpty() || !moduleName.isEmpty()) { Method mainEntryPoint; Class mainClass; @@ -409,15 +421,7 @@ private int buildImage(String[] arguments, ImageClassLoader classLoader) { if (compilationExecutor != null) { compilationExecutor.shutdownNow(); } - if (e.getReason().isPresent()) { - if (!e.getReason().get().isEmpty()) { - NativeImageGeneratorRunner.info(e.getReason().get()); - } - return 0; - } else { - /* InterruptImageBuilding without explicit reason is exit code 3 */ - return 3; - } + throw e; } catch (FallbackFeature.FallbackImageRequest e) { if (FallbackExecutor.class.getName().equals(SubstrateOptions.Class.getValue())) { NativeImageGeneratorRunner.reportFatalError(e, "FallbackImageRequest while building fallback image."); @@ -496,7 +500,7 @@ public static String getJavaVersion() { * @param e error to be reported. */ protected static void reportFatalError(Throwable e) { - System.err.print("Fatal error:"); + System.err.print("Fatal error: "); e.printStackTrace(); } @@ -565,8 +569,8 @@ private static void warn(String msg) { System.err.println("Warning: " + msg); } - public int build(String[] args, ImageClassLoader imageClassLoader) { - return buildImage(args, imageClassLoader); + public int build(ImageClassLoader imageClassLoader) { + return buildImage(imageClassLoader); } /** @@ -586,12 +590,12 @@ public static void main(String[] args) { ModuleSupport.exportAndOpenAllPackagesToUnnamed("jdk.internal.vm.compiler.management", true); ModuleSupport.exportAndOpenAllPackagesToUnnamed("com.oracle.graal.graal_enterprise", true); ModuleSupport.exportAndOpenPackageToUnnamed("java.base", "jdk.internal.loader", false); - if (JavaVersionUtil.JAVA_SPEC >= 15) { + if (JavaVersionUtil.JAVA_SPEC >= 17) { ModuleSupport.exportAndOpenPackageToUnnamed("java.base", "jdk.internal.misc", false); } ModuleSupport.exportAndOpenPackageToUnnamed("java.base", "sun.text.spi", false); ModuleSupport.exportAndOpenPackageToUnnamed("java.base", "jdk.internal.org.objectweb.asm", false); - if (JavaVersionUtil.JAVA_SPEC >= 16) { + if (JavaVersionUtil.JAVA_SPEC >= 17) { ModuleSupport.exportAndOpenPackageToUnnamed("java.base", "sun.reflect.annotation", false); ModuleSupport.exportAndOpenPackageToUnnamed("java.base", "sun.security.jca", false); ModuleSupport.exportAndOpenPackageToUnnamed("jdk.jdeps", "com.sun.tools.classfile", false); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java index 606dbf6322a4..767adf4bba53 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java @@ -25,6 +25,8 @@ package com.oracle.svm.hosted; +import static com.oracle.svm.core.jdk.Resources.RESOURCES_INTERNAL_PATH_SEPARATOR; + import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -62,7 +64,7 @@ import com.oracle.svm.core.configure.ResourceConfigurationParser; import com.oracle.svm.core.configure.ResourcesRegistry; import com.oracle.svm.core.jdk.Resources; -import com.oracle.svm.core.jdk.localization.LocalizationFeature; +import com.oracle.svm.hosted.jdk.localization.LocalizationFeature; import com.oracle.svm.core.jdk.resources.NativeImageResourceFileAttributes; import com.oracle.svm.core.jdk.resources.NativeImageResourceFileAttributesView; import com.oracle.svm.core.jdk.resources.NativeImageResourceFileSystem; @@ -71,6 +73,7 @@ import com.oracle.svm.core.option.LocatableMultiOptionValue; import com.oracle.svm.core.util.ClasspathUtils; import com.oracle.svm.core.util.UserError; +import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; import com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl; import com.oracle.svm.hosted.config.ConfigurationParserUtils; @@ -217,7 +220,7 @@ public void duringAnalysis(DuringAnalysisAccess access) { */ ImageClassLoader loader = accessImpl.imageClassLoader; - Stream.concat(loader.modulepath().stream(), loader.classpath().stream()).forEach(classpathFile -> { + Stream.concat(loader.modulepath().stream(), loader.classpath().stream()).distinct().forEach(classpathFile -> { try { if (Files.isDirectory(classpathFile)) { scanDirectory(debugContext, classpathFile, includePatterns, excludePatterns); @@ -268,7 +271,7 @@ private static void scanDirectory(DebugContext debugContext, Path root, Pattern[ /* Resources always use / as the separator, as do our resource inclusion patterns */ String relativeFilePath; if (entry != root) { - relativeFilePath = root.relativize(entry).toString().replace(File.separatorChar, '/'); + relativeFilePath = root.relativize(entry).toString().replace(File.separatorChar, RESOURCES_INTERNAL_PATH_SEPARATOR); allEntries.add(relativeFilePath); } else { relativeFilePath = ""; @@ -291,7 +294,7 @@ private static void scanDirectory(DebugContext debugContext, Path root, Pattern[ } for (String entry : allEntries) { - int last = entry.lastIndexOf('/'); + int last = entry.lastIndexOf(RESOURCES_INTERNAL_PATH_SEPARATOR); String key = last == -1 ? "" : entry.substring(0, last); List dirContent = matchedDirectoryResources.get(key); if (dirContent != null && !dirContent.contains(entry)) { @@ -328,14 +331,16 @@ private static void scanJar(DebugContext debugContext, Path jarPath, Pattern[] i } private static boolean matches(Pattern[] includePatterns, Pattern[] excludePatterns, String relativePath) { + VMError.guarantee(!relativePath.contains("\\"), "Resource path contains backslash!"); + String relativePathWithTrailingSlash = relativePath + RESOURCES_INTERNAL_PATH_SEPARATOR; for (Pattern p : excludePatterns) { - if (p.matcher(relativePath).matches()) { + if (p.matcher(relativePath).matches() || p.matcher(relativePathWithTrailingSlash).matches()) { return false; } } for (Pattern p : includePatterns) { - if (p.matcher(relativePath).matches()) { + if (p.matcher(relativePath).matches() || p.matcher(relativePathWithTrailingSlash).matches()) { return true; } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java index 083e3b7fdf51..faa649e0e9b1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java @@ -43,10 +43,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.ForkJoinPool; import java.util.function.BiConsumer; -import com.oracle.graal.pointsto.BigBang; import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; import org.graalvm.compiler.debug.MethodFilter; @@ -69,6 +67,7 @@ import org.graalvm.nativeimage.hosted.Feature.DuringAnalysisAccess; import org.graalvm.util.GuardedAnnotationAccess; +import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.api.PointstoOptions; @@ -80,6 +79,7 @@ import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisPolicy; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.RuntimeAssertionsSupport; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; @@ -103,7 +103,6 @@ import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.core.util.HostedStringDeduplication; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.c.GraalAccess; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.code.InliningUtilities; import com.oracle.svm.hosted.meta.HostedType; @@ -125,7 +124,6 @@ public class SVMHost implements HostVM { private final Map> forbiddenTypes; private final Platform platform; private final OptionValues options; - private final ForkJoinPool executor; private final ClassLoader classLoader; private final ClassInitializationSupport classInitializationSupport; private final HostedStringDeduplication stringTable; @@ -149,10 +147,9 @@ public class SVMHost implements HostVM { private static final Method getNestHostMethod = JavaVersionUtil.JAVA_SPEC >= 11 ? ReflectionUtil.lookupMethod(Class.class, "getNestHost") : null; - public SVMHost(OptionValues options, ForkJoinPool executor, ClassLoader classLoader, ClassInitializationSupport classInitializationSupport, + public SVMHost(OptionValues options, ClassLoader classLoader, ClassInitializationSupport classInitializationSupport, UnsafeAutomaticSubstitutionProcessor automaticSubstitutions, Platform platform) { this.options = options; - this.executor = executor; this.classLoader = classLoader; this.classInitializationSupport = classInitializationSupport; this.stringTable = HostedStringDeduplication.singleton(); @@ -211,11 +208,6 @@ public OptionValues options() { return options; } - @Override - public ForkJoinPool executor() { - return executor; - } - @Override public Instance createGraphBuilderPhase(HostedProviders providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { return new AnalysisGraphBuilderPhase(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext, providers.getWordTypes()); @@ -399,9 +391,6 @@ private DynamicHub createHub(AnalysisType type) { */ String sourceFileName = stringTable.deduplicate(type.getSourceFileName(), true); - /* JDK 15 added support for Hidden Classes. Record if this javaClass is hidden. */ - boolean isHidden = SubstrateUtil.isHiddenClass(javaClass); - Class nestHost = null; if (JavaVersionUtil.JAVA_SPEC >= 11) { try { @@ -411,6 +400,7 @@ private DynamicHub createHub(AnalysisType type) { } } + boolean isHidden = SubstrateUtil.isHiddenClass(javaClass); boolean isRecord = RecordSupport.singleton().isRecord(javaClass); boolean assertionStatus = RuntimeAssertionsSupport.singleton().desiredAssertionStatus(javaClass); @@ -750,6 +740,12 @@ public boolean platformSupported(AnalysisUniverse universe, AnnotatedElement ele return false; } } + if (element instanceof Class) { + Package p = ((Class) element).getPackage(); + if (p != null && !platformSupported(universe, p)) { + return false; + } + } Platforms platformsAnnotation = GuardedAnnotationAccess.getAnnotation(element, Platforms.class); if (platform == null || platformsAnnotation == null) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java index 1c1aa6a8a8d8..7b3a05ae5474 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java @@ -266,6 +266,10 @@ public void duringSetup(DuringSetupAccess a) { rci.rerunInitialization(clazz(access, "com.sun.crypto.provider.SunJCE$SecureRandomHolder"), "for substitutions"); rci.rerunInitialization(clazz(access, "sun.security.krb5.Confounder"), "for substitutions"); + if (JavaVersionUtil.JAVA_SPEC >= 17) { + rci.rerunInitialization(clazz(access, "sun.security.jca.JCAUtil"), "JCAUtil.def holds a SecureRandom."); + } + /* * When SSLContextImpl$DefaultManagersHolder sets-up the TrustManager in its initializer it * gets the value of the -Djavax.net.ssl.trustStore and -Djavax.net.ssl.trustStorePassword @@ -296,7 +300,7 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { registerServiceReachabilityHandlers(access); } - if (JavaVersionUtil.JAVA_SPEC < 16) { + if (JavaVersionUtil.JAVA_SPEC <= 11) { // https://bugs.openjdk.java.net/browse/JDK-8235710 access.registerReachabilityHandler(SecurityServicesFeature::linkSunEC, method(access, "sun.security.ec.ECDSASignature", "signDigest", byte[].class, byte[].class, byte[].class, byte[].class, int.class), @@ -314,8 +318,8 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { if (isWindows()) { access.registerReachabilityHandler(SecurityServicesFeature::registerSunMSCAPIConfig, clazz(access, "sun.security.mscapi.SunMSCAPI")); // statically linking sunmscapi conflicts with sunEC - // after the removal of sunEC in jdk 16, we can statically link sunmscapi - if (JavaVersionUtil.JAVA_SPEC >= 16) { + // after the removal of sunEC in jdk 17, we can statically link sunmscapi + if (JavaVersionUtil.JAVA_SPEC >= 17) { access.registerReachabilityHandler(SecurityServicesFeature::linkSunMSCAPI, clazz(access, "sun.security.mscapi.SunMSCAPI")); /* Resolve calls to sun_security_mscapi* as builtIn. */ PlatformNativeLibrarySupport.singleton().addBuiltinPkgNativePrefix("sun_security_mscapi"); @@ -736,10 +740,10 @@ private static void registerForReflection(Class clazz) { @SuppressWarnings("unchecked") private Function constructVerificationCacheCleaner() { /* - * Before JDK 16, the verification cache was a Provider -> Verification result + * For JDK 8 and JDK 11, the verification cache is a Provider -> Verification result * IdentityHashMap. */ - if (JavaVersionUtil.JAVA_SPEC <= 15) { + if (JavaVersionUtil.JAVA_SPEC <= 11) { return obj -> { Map original = (Map) obj; Map verificationResults = new IdentityHashMap<>(original); @@ -750,7 +754,7 @@ private Function constructVerificationCacheCleaner() { }; } /* - * For JDK 16 and later, the verification cache is an IdentityWrapper -> Verification result + * For JDK 17 and later, the verification cache is an IdentityWrapper -> Verification result * ConcurrentHashMap. The IdentityWrapper contains the actual provider in the 'obj' field. */ Class identityWrapper = loader.findClassOrFail("javax.crypto.JceSecurity$IdentityWrapper"); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SubstitutionReportFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SubstitutionReportFeature.java index 26b4d8b89c50..0fcfc866c73c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SubstitutionReportFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SubstitutionReportFeature.java @@ -24,29 +24,31 @@ */ package com.oracle.svm.hosted; +import java.security.CodeSource; +import java.util.Comparator; +import java.util.Map; +import java.util.TreeMap; +import java.util.function.Function; + +import org.graalvm.compiler.options.Option; +import org.graalvm.nativeimage.hosted.Feature; + import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.reports.ReportUtils; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.core.option.HostedOptionKey; -import com.oracle.svm.hosted.c.GraalAccess; import com.oracle.svm.hosted.substitute.SubstitutionField; import com.oracle.svm.hosted.substitute.SubstitutionMethod; import com.oracle.svm.hosted.substitute.SubstitutionType; + import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; -import org.graalvm.compiler.options.Option; -import org.graalvm.nativeimage.hosted.Feature; - -import java.security.CodeSource; -import java.util.Comparator; -import java.util.Map; -import java.util.TreeMap; -import java.util.function.Function; @AutomaticFeature public class SubstitutionReportFeature implements Feature { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/AnnotationsProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/AnnotationsProcessor.java new file mode 100644 index 000000000000..4358e8ca8eeb --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/AnnotationsProcessor.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.analysis; + +import java.lang.annotation.Annotation; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.util.AnalysisError; +import com.oracle.svm.core.hub.AnnotationsEncoding; + +public class AnnotationsProcessor { + + public static Object encodeAnnotations(AnalysisMetaAccess metaAccess, Annotation[] allAnnotations, Annotation[] declaredAnnotations, Object oldEncoding) { + Object newEncoding; + if (allAnnotations.length == 0 && declaredAnnotations.length == 0) { + newEncoding = null; + } else { + Set all = new HashSet<>(); + Collections.addAll(all, allAnnotations); + Collections.addAll(all, declaredAnnotations); + final Set usedAnnotations = all.stream() + .filter(a -> { + try { + AnalysisType annotationClass = metaAccess.lookupJavaType(a.getClass()); + return isAnnotationUsed(annotationClass); + } catch (AnalysisError.TypeNotFoundError e) { + /* + * Silently ignore the annotation if its type was not discovered + * by the static analysis. + */ + return false; + } + }).collect(Collectors.toSet()); + Set usedDeclared = filterUsedAnnotation(usedAnnotations, declaredAnnotations); + newEncoding = usedAnnotations.size() == 0 + ? null + : AnnotationsEncoding.encodeAnnotations(usedAnnotations, usedDeclared); + } + + /* + * Return newEncoding only if the value is different from oldEncoding. Without this guard, + * for tests that do runtime compilation, the field appears as being continuously updated + * during BigBang.checkObjectGraph. + */ + if (oldEncoding != null && oldEncoding.equals(newEncoding)) { + return oldEncoding; + } else { + return newEncoding; + } + } + + /** + * We only want annotations in the native image heap that are "used" at run time. In our case, + * "used" means that the annotation interface is used at least in a type check. This leaves one + * case where Substrate VM behaves differently than a normal Java VM: When you just query the + * number of annotations on a class, then we might return a lower number. + */ + private static boolean isAnnotationUsed(AnalysisType annotationType) { + if (annotationType.isReachable()) { + return true; + } + assert annotationType.getInterfaces().length == 1 : annotationType; + + AnalysisType annotationInterfaceType = annotationType.getInterfaces()[0]; + return annotationInterfaceType.isReachable(); + } + + private static Set filterUsedAnnotation(Set used, Annotation[] rest) { + if (rest == null) { + return null; + } + + Set restUsed = new HashSet<>(); + for (Annotation a : rest) { + if (used.contains(a)) { + restUsed.add(a); + } + } + return restUsed; + } + +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java new file mode 100644 index 000000000000..760d97244dc6 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.analysis; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedType; +import java.lang.reflect.MalformedParameterizedTypeException; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.Arrays; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; +import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; +import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.meta.AnalysisUniverse; +import com.oracle.svm.core.hub.AnnotatedSuperInfo; +import com.oracle.svm.core.hub.DynamicHub; +import com.oracle.svm.core.hub.GenericInfo; +import com.oracle.svm.core.meta.SubstrateObjectConstant; +import com.oracle.svm.hosted.SVMHost; + +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaType; + +public class DynamicHubInitializer { + + private final SVMHost hostVM; + private final AnalysisUniverse universe; + private final AnalysisMetaAccess metaAccess; + private final UnsupportedFeatures unsupportedFeatures; + private final ConstantReflectionProvider constantReflection; + + private final Map genericInterfacesMap; + private final Map annotatedInterfacesMap; + private final Map interfacesEncodings; + + public DynamicHubInitializer(AnalysisUniverse universe, AnalysisMetaAccess metaAccess, + UnsupportedFeatures unsupportedFeatures, ConstantReflectionProvider constantReflection) { + this.hostVM = (SVMHost) universe.hostVM(); + this.universe = universe; + this.metaAccess = metaAccess; + this.unsupportedFeatures = unsupportedFeatures; + this.constantReflection = constantReflection; + + this.genericInterfacesMap = new ConcurrentHashMap<>(); + this.annotatedInterfacesMap = new ConcurrentHashMap<>(); + this.interfacesEncodings = new ConcurrentHashMap<>(); + } + + public void initializeMetaData(AnalysisType type) { + assert type.isReachable(); + DynamicHub hub = hostVM.dynamicHub(type); + if (hub.getGenericInfo() == null) { + fillGenericInfo(type, hub); + } + if (hub.getAnnotatedSuperInfo() == null) { + fillAnnotatedSuperInfo(type, hub); + } + + if (type.getJavaKind() == JavaKind.Object) { + if (type.isArray()) { + hub.getComponentHub().setArrayHub(hub); + } + + try { + AnalysisType enclosingType = type.getEnclosingType(); + if (enclosingType != null) { + hub.setEnclosingClass(hostVM.dynamicHub(enclosingType)); + } + } catch (UnsupportedFeatureException ex) { + unsupportedFeatures.addMessage(type.toJavaName(true), null, ex.getMessage(), null, ex); + } + + if (hub.getInterfacesEncoding() == null) { + fillInterfaces(type, hub); + } + + /* + * Support for Java annotations. + */ + try { + /* + * Get the annotations from the wrapped type since AnalysisType.getAnnotations() + * defends against JDK-7183985, and we want to get the original behavior. + */ + Annotation[] annotations = type.getWrappedWithoutResolve().getAnnotations(); + Annotation[] declared = type.getWrappedWithoutResolve().getDeclaredAnnotations(); + hub.setAnnotationsEncoding(AnnotationsProcessor.encodeAnnotations(metaAccess, annotations, declared, hub.getAnnotationsEncoding())); + } catch (ArrayStoreException e) { + /* If we hit JDK-7183985 just encode the exception. */ + hub.setAnnotationsEncoding(e); + } + + /* + * Support for Java enumerations. + */ + if (type.isEnum() && hub.shouldInitEnumConstants()) { + if (hostVM.getClassInitializationSupport().shouldInitializeAtRuntime(type)) { + hub.initEnumConstantsAtRuntime(type.getJavaClass()); + } else { + /* + * We want to retrieve the enum constant array that is maintained as a private + * static field in the enumeration class. We do not want a copy because that + * would mean we have the array twice in the native image: as the static field, + * and in the enumConstant field of DynamicHub. The only way to get the original + * value is via a reflective field access, and we even have to guess the field + * name. + */ + AnalysisField found = null; + for (AnalysisField f : type.getStaticFields()) { + if (f.getName().endsWith("$VALUES")) { + if (found != null) { + /* + * Enumeration has more than one static field with enumeration + * values. Bailout and use Class.getEnumConstants() to get the value + * instead. + */ + found = null; + break; + } + found = f; + } + } + Enum[] enumConstants; + if (found == null) { + /* + * We could not find a unique $VALUES field, so we use the value returned by + * Class.getEnumConstants(). This is not ideal since + * Class.getEnumConstants() returns a copy of the array, so we will have two + * arrays with the same content in the image heap, but it is better than + * failing image generation. + */ + enumConstants = (Enum[]) type.getJavaClass().getEnumConstants(); + } else { + enumConstants = (Enum[]) SubstrateObjectConstant.asObject(constantReflection.readFieldValue(found, null)); + assert enumConstants != null; + } + hub.initEnumConstants(enumConstants); + } + } + } + } + + static class GenericInterfacesEncodingKey { + final Type[] interfaces; + + GenericInterfacesEncodingKey(Type[] aInterfaces) { + this.interfaces = aInterfaces; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof GenericInterfacesEncodingKey && Arrays.equals(interfaces, ((GenericInterfacesEncodingKey) obj).interfaces); + } + + @Override + public int hashCode() { + return Arrays.hashCode(interfaces); + } + } + + /** Modified copy of {@link Arrays#equals(Object[], Object[])}. */ + private static boolean shallowEquals(Object[] a, Object[] a2) { + if (a == a2) { + return true; + } else if (a == null || a2 == null) { + return false; + } + int length = a.length; + if (a2.length != length) { + return false; + } + for (int i = 0; i < length; i++) { + /* Modification: use reference equality. */ + if (a[i] != a2[i]) { + return false; + } + } + return true; + } + + /** Modified copy of {@link Arrays#hashCode(Object[])}. */ + private static int shallowHashCode(Object[] a) { + if (a == null) { + return 0; + } + int result = 1; + + for (Object element : a) { + /* Modification: use identity hash code. */ + result = 31 * result + System.identityHashCode(element); + } + return result; + } + + static class AnnotatedInterfacesEncodingKey { + final AnnotatedType[] interfaces; + + AnnotatedInterfacesEncodingKey(AnnotatedType[] aInterfaces) { + this.interfaces = aInterfaces; + } + + /* + * After JDK 11, the implementation of hashCode() and equals() for the implementation + * classes of annotated types can lead to the reification of generic bounds, which can lead + * to TypeNotPresentException when the class path is incomplete. Therefore, we use shallow + * implementations that only depend on the identity hash code and reference equality. This + * is the same behavior as on JDK 8 and JDK 11 anyway. + */ + + @Override + public boolean equals(Object obj) { + return obj instanceof AnnotatedInterfacesEncodingKey && shallowEquals(interfaces, ((AnnotatedInterfacesEncodingKey) obj).interfaces); + } + + @Override + public int hashCode() { + return shallowHashCode(interfaces); + } + } + + private void fillGenericInfo(AnalysisType type, DynamicHub hub) { + Class javaClass = type.getJavaClass(); + + TypeVariable[] typeParameters = javaClass.getTypeParameters(); + + Type[] allGenericInterfaces; + try { + allGenericInterfaces = javaClass.getGenericInterfaces(); + } catch (MalformedParameterizedTypeException | TypeNotPresentException | LinkageError t) { + /* + * Loading generic interfaces can fail due to missing types. Ignore the exception and + * return an empty array. + */ + allGenericInterfaces = new Type[0]; + } + + Type[] genericInterfaces = Arrays.stream(allGenericInterfaces).filter(this::isTypeAllowed).toArray(Type[]::new); + Type[] cachedGenericInterfaces; + try { + cachedGenericInterfaces = genericInterfacesMap.computeIfAbsent(new GenericInterfacesEncodingKey(genericInterfaces), k -> genericInterfaces); + } catch (MalformedParameterizedTypeException | TypeNotPresentException | LinkageError t) { + /* + * Computing the hash code of generic interfaces can fail due to missing types. Ignore + * the exception and proceed without caching. De-duplication of generic interfaces is an + * optimization and not necessary for correctness. + */ + cachedGenericInterfaces = genericInterfaces; + } + + Type genericSuperClass; + try { + genericSuperClass = javaClass.getGenericSuperclass(); + } catch (MalformedParameterizedTypeException | TypeNotPresentException | LinkageError t) { + /* + * Loading the generic super class can fail due to missing types. Ignore the exception + * and return null. + */ + genericSuperClass = null; + } + if (!isTypeAllowed(genericSuperClass)) { + genericSuperClass = null; + } + hub.setGenericInfo(GenericInfo.factory(typeParameters, cachedGenericInterfaces, genericSuperClass)); + } + + private void fillAnnotatedSuperInfo(AnalysisType type, DynamicHub hub) { + Class javaClass = type.getJavaClass(); + + AnnotatedType annotatedSuperclass; + try { + annotatedSuperclass = javaClass.getAnnotatedSuperclass(); + } catch (MalformedParameterizedTypeException | TypeNotPresentException | LinkageError t) { + /* + * Loading the annotated super class can fail due to missing types. Ignore the exception + * and return null. + */ + annotatedSuperclass = null; + } + if (annotatedSuperclass != null && !isTypeAllowed(annotatedSuperclass.getType())) { + annotatedSuperclass = null; + } + + AnnotatedType[] allAnnotatedInterfaces; + try { + allAnnotatedInterfaces = javaClass.getAnnotatedInterfaces(); + } catch (MalformedParameterizedTypeException | TypeNotPresentException | LinkageError t) { + /* + * Loading annotated interfaces can fail due to missing types. Ignore the exception and + * return an empty array. + */ + allAnnotatedInterfaces = new AnnotatedType[0]; + } + + AnnotatedType[] annotatedInterfaces = Arrays.stream(allAnnotatedInterfaces) + .filter(ai -> isTypeAllowed(ai.getType())).toArray(AnnotatedType[]::new); + AnnotatedType[] cachedAnnotatedInterfaces = annotatedInterfacesMap.computeIfAbsent( + new AnnotatedInterfacesEncodingKey(annotatedInterfaces), k -> annotatedInterfaces); + hub.setAnnotatedSuperInfo(AnnotatedSuperInfo.factory(annotatedSuperclass, cachedAnnotatedInterfaces)); + } + + private boolean isTypeAllowed(Type t) { + if (t instanceof Class) { + Optional resolved = metaAccess.optionalLookupJavaType((Class) t); + return resolved.isPresent() && hostVM.platformSupported(universe, resolved.get()); + } + return true; + } + + class InterfacesEncodingKey { + final AnalysisType[] aInterfaces; + + InterfacesEncodingKey(AnalysisType[] aInterfaces) { + this.aInterfaces = aInterfaces; + } + + DynamicHub[] createHubs() { + DynamicHub[] hubs = new DynamicHub[aInterfaces.length]; + for (int i = 0; i < hubs.length; i++) { + hubs[i] = hostVM.dynamicHub(aInterfaces[i]); + } + return hubs; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof InterfacesEncodingKey && Arrays.equals(aInterfaces, ((InterfacesEncodingKey) obj).aInterfaces); + } + + @Override + public int hashCode() { + return Arrays.hashCode(aInterfaces); + } + } + + /** + * Fill array returned by Class.getInterfaces(). + */ + private void fillInterfaces(AnalysisType type, DynamicHub hub) { + AnalysisType[] aInterfaces = type.getInterfaces(); + if (aInterfaces.length == 0) { + hub.setInterfacesEncoding(null); + } else if (aInterfaces.length == 1) { + hub.setInterfacesEncoding(hostVM.dynamicHub(aInterfaces[0])); + } else { + /* + * Many interfaces arrays are the same, e.g., all arrays implement the same two + * interfaces. We want to avoid duplicate arrays with the same content in the native + * image heap. + */ + hub.setInterfacesEncoding(interfacesEncodings.computeIfAbsent(new InterfacesEncodingKey(aInterfaces), InterfacesEncodingKey::createHubs)); + } + } + +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java index 58a4f50240b4..2278867cf597 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java @@ -28,56 +28,40 @@ import static com.oracle.svm.hosted.NativeImageOptions.MaxReachableTypes; import static jdk.vm.ci.common.JVMCIError.shouldNotReachHere; -import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedType; -import java.lang.reflect.MalformedParameterizedTypeException; import java.lang.reflect.Modifier; -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; -import java.util.Optional; import java.util.Set; import java.util.concurrent.ForkJoinPool; import java.util.regex.Pattern; -import java.util.stream.Collectors; -import com.oracle.svm.hosted.HostedConfiguration; import org.graalvm.compiler.core.common.SuppressSVMWarnings; import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.options.OptionValues; import org.graalvm.word.WordBase; -import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.ObjectScanner; import com.oracle.graal.pointsto.ObjectScanner.ScanReason; -import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; +import com.oracle.graal.pointsto.PointsToAnalysis; +import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; import com.oracle.graal.pointsto.flow.MethodTypeFlow; import com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder; import com.oracle.graal.pointsto.flow.TypeFlow; import com.oracle.graal.pointsto.meta.AnalysisField; -import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.graal.pointsto.reports.CallTreePrinter; -import com.oracle.graal.pointsto.util.AnalysisError.TypeNotFoundError; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.annotate.UnknownObjectField; import com.oracle.svm.core.annotate.UnknownPrimitiveField; import com.oracle.svm.core.graal.meta.SubstrateReplacements; -import com.oracle.svm.core.hub.AnnotatedSuperInfo; -import com.oracle.svm.core.hub.AnnotationsEncoding; -import com.oracle.svm.core.hub.DynamicHub; -import com.oracle.svm.core.hub.GenericInfo; import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.util.UserError; +import com.oracle.svm.hosted.HostedConfiguration; import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.meta.HostedType; import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor; @@ -88,17 +72,14 @@ public class NativeImagePointsToAnalysis extends PointsToAnalysis implements Inflation { private Set handledUnknownValueFields; - private Map genericInterfacesMap; - private Map annotatedInterfacesMap; - private Map interfacesEncodings; private final Pattern illegalCalleesPattern; private final Pattern targetCallersPattern; private final AnnotationSubstitutionProcessor annotationSubstitutionProcessor; + private final DynamicHubInitializer dynamicHubInitializer; public NativeImagePointsToAnalysis(OptionValues options, AnalysisUniverse universe, HostedProviders providers, AnnotationSubstitutionProcessor annotationSubstitutionProcessor, - ForkJoinPool executor, - Runnable heartbeatCallback) { + ForkJoinPool executor, Runnable heartbeatCallback, UnsupportedFeatures unsupportedFeatures) { super(options, universe, providers, universe.hostVM(), executor, heartbeatCallback, new SubstrateUnsupportedFeatures(), SubstrateOptions.parseOnce()); this.annotationSubstitutionProcessor = annotationSubstitutionProcessor; @@ -109,9 +90,7 @@ public NativeImagePointsToAnalysis(OptionValues options, AnalysisUniverse univer illegalCalleesPattern = buildPrefixMatchPattern(illegalCallees); handledUnknownValueFields = new HashSet<>(); - genericInterfacesMap = new HashMap<>(); - annotatedInterfacesMap = new HashMap<>(); - interfacesEncodings = new HashMap<>(); + dynamicHubInitializer = new DynamicHubInitializer(universe, metaAccess, unsupportedFeatures, providers.getConstantReflection()); } @Override @@ -122,7 +101,7 @@ public MethodTypeFlowBuilder createMethodTypeFlowBuilder(PointsToAnalysis bb, Me @Override protected void checkObjectGraph(ObjectScanner objectScanner) { universe.getFields().forEach(this::handleUnknownValueField); - universe.getTypes().stream().filter(AnalysisType::isReachable).forEach(this::checkType); + universe.getTypes().stream().filter(AnalysisType::isReachable).forEach(dynamicHubInitializer::initializeMetaData); /* Scan hubs of all types that end up in the native image. */ universe.getTypes().stream().filter(AnalysisType::isReachable).forEach(type -> scanHub(objectScanner, type)); @@ -133,107 +112,10 @@ public SVMHost getHostVM() { return (SVMHost) hostVM; } - private void checkType(AnalysisType type) { - assert type.isReachable(); - DynamicHub hub = getHostVM().dynamicHub(type); - if (hub.getGenericInfo() == null) { - fillGenericInfo(type, hub); - } - if (hub.getAnnotatedSuperInfo() == null) { - fillAnnotatedSuperInfo(type, hub); - } - - if (type.getJavaKind() == JavaKind.Object) { - if (type.isArray()) { - hub.getComponentHub().setArrayHub(hub); - } - - try { - AnalysisType enclosingType = type.getEnclosingType(); - if (enclosingType != null) { - hub.setEnclosingClass(getHostVM().dynamicHub(enclosingType)); - } - } catch (UnsupportedFeatureException ex) { - getUnsupportedFeatures().addMessage(type.toJavaName(true), null, ex.getMessage(), null, ex); - } - - if (hub.getInterfacesEncoding() == null) { - fillInterfaces(type, hub); - } - - /* - * Support for Java annotations. - */ - try { - /* - * Get the annotations from the wrapped type since AnalysisType.getAnnotations() - * defends against JDK-7183985 and we want to get the original behavior. - */ - Annotation[] annotations = type.getWrappedWithoutResolve().getAnnotations(); - Annotation[] declared = type.getWrappedWithoutResolve().getDeclaredAnnotations(); - hub.setAnnotationsEncoding(encodeAnnotations(metaAccess, annotations, declared, hub.getAnnotationsEncoding())); - } catch (ArrayStoreException e) { - /* If we hit JDK-7183985 just encode the exception. */ - hub.setAnnotationsEncoding(e); - } - - /* - * Support for Java enumerations. - */ - if (type.isEnum() && hub.shouldInitEnumConstants()) { - if (getHostVM().getClassInitializationSupport().shouldInitializeAtRuntime(type)) { - hub.initEnumConstantsAtRuntime(type.getJavaClass()); - } else { - /* - * We want to retrieve the enum constant array that is maintained as a private - * static field in the enumeration class. We do not want a copy because that - * would mean we have the array twice in the native image: as the static field, - * and in the enumConstant field of DynamicHub. The only way to get the original - * value is via a reflective field access, and we even have to guess the field - * name. - */ - AnalysisField found = null; - for (AnalysisField f : type.getStaticFields()) { - if (f.getName().endsWith("$VALUES")) { - if (found != null) { - /* - * Enumeration has more than one static field with enumeration - * values. Bailout and use Class.getEnumConstants() to get the value - * instead. - */ - found = null; - break; - } - found = f; - } - } - Enum[] enumConstants; - if (found == null) { - /* - * We could not find a unique $VALUES field, so we use the value returned by - * Class.getEnumConstants(). This is not ideal since - * Class.getEnumConstants() returns a copy of the array, so we will have two - * arrays with the same content in the image heap, but it is better than - * failing image generation. - */ - enumConstants = (Enum[]) type.getJavaClass().getEnumConstants(); - } else { - enumConstants = (Enum[]) SubstrateObjectConstant.asObject(getConstantReflectionProvider().readFieldValue(found, null)); - assert enumConstants != null; - } - hub.initEnumConstants(enumConstants); - } - } - } - } - @Override public void cleanupAfterAnalysis() { super.cleanupAfterAnalysis(); handledUnknownValueFields = null; - genericInterfacesMap = null; - annotatedInterfacesMap = null; - interfacesEncodings = null; } @Override @@ -255,220 +137,6 @@ public AnnotationSubstitutionProcessor getAnnotationSubstitutionProcessor() { return annotationSubstitutionProcessor; } - static class GenericInterfacesEncodingKey { - final Type[] interfaces; - - GenericInterfacesEncodingKey(Type[] aInterfaces) { - this.interfaces = aInterfaces; - } - - @Override - public boolean equals(Object obj) { - return obj instanceof GenericInterfacesEncodingKey && Arrays.equals(interfaces, ((GenericInterfacesEncodingKey) obj).interfaces); - } - - @Override - public int hashCode() { - return Arrays.hashCode(interfaces); - } - } - - /** Modified copy of {@link Arrays#equals(Object[], Object[])}. */ - private static boolean shallowEquals(Object[] a, Object[] a2) { - if (a == a2) { - return true; - } else if (a == null || a2 == null) { - return false; - } - int length = a.length; - if (a2.length != length) { - return false; - } - for (int i = 0; i < length; i++) { - /* Modification: use reference equality. */ - if (a[i] != a2[i]) { - return false; - } - } - return true; - } - - /** Modified copy of {@link Arrays#hashCode(Object[])}. */ - private static int shallowHashCode(Object[] a) { - if (a == null) { - return 0; - } - int result = 1; - - for (Object element : a) { - /* Modification: use identity hash code. */ - result = 31 * result + System.identityHashCode(element); - } - return result; - } - - static class AnnotatedInterfacesEncodingKey { - final AnnotatedType[] interfaces; - - AnnotatedInterfacesEncodingKey(AnnotatedType[] aInterfaces) { - this.interfaces = aInterfaces; - } - - /* - * JDK 12 introduced a broken implementation of hashCode() and equals() for the - * implementation classes of annotated types, leading to an infinite recursion. Tracked as - * JDK-8224012. As a workaround, we use shallow implementations that only depend on the - * identity hash code and reference equality. This is the same behavior as on JDK 8 and JDK - * 11 anyway. - */ - - @Override - public boolean equals(Object obj) { - return obj instanceof AnnotatedInterfacesEncodingKey && shallowEquals(interfaces, ((AnnotatedInterfacesEncodingKey) obj).interfaces); - } - - @Override - public int hashCode() { - return shallowHashCode(interfaces); - } - } - - private void fillGenericInfo(AnalysisType type, DynamicHub hub) { - Class javaClass = type.getJavaClass(); - - TypeVariable[] typeParameters = javaClass.getTypeParameters(); - - Type[] allGenericInterfaces; - try { - allGenericInterfaces = javaClass.getGenericInterfaces(); - } catch (MalformedParameterizedTypeException | TypeNotPresentException | LinkageError t) { - /* - * Loading generic interfaces can fail due to missing types. Ignore the exception and - * return an empty array. - */ - allGenericInterfaces = new Type[0]; - } - - Type[] genericInterfaces = Arrays.stream(allGenericInterfaces).filter(this::isTypeAllowed).toArray(Type[]::new); - Type[] cachedGenericInterfaces; - try { - cachedGenericInterfaces = genericInterfacesMap.computeIfAbsent(new GenericInterfacesEncodingKey(genericInterfaces), k -> genericInterfaces); - } catch (MalformedParameterizedTypeException | TypeNotPresentException | LinkageError t) { - /* - * Computing the hash code of generic interfaces can fail due to missing types. Ignore - * the exception and proceed without caching. De-duplication of generic interfaces is an - * optimization and not necessary for correctness. - */ - cachedGenericInterfaces = genericInterfaces; - } - - Type genericSuperClass; - try { - genericSuperClass = javaClass.getGenericSuperclass(); - } catch (MalformedParameterizedTypeException | TypeNotPresentException | LinkageError t) { - /* - * Loading the generic super class can fail due to missing types. Ignore the exception - * and return null. - */ - genericSuperClass = null; - } - if (!isTypeAllowed(genericSuperClass)) { - genericSuperClass = null; - } - hub.setGenericInfo(GenericInfo.factory(typeParameters, cachedGenericInterfaces, genericSuperClass)); - } - - private void fillAnnotatedSuperInfo(AnalysisType type, DynamicHub hub) { - Class javaClass = type.getJavaClass(); - - AnnotatedType annotatedSuperclass; - try { - annotatedSuperclass = javaClass.getAnnotatedSuperclass(); - } catch (MalformedParameterizedTypeException | TypeNotPresentException | LinkageError t) { - /* - * Loading the annotated super class can fail due to missing types. Ignore the exception - * and return null. - */ - annotatedSuperclass = null; - } - if (annotatedSuperclass != null && !isTypeAllowed(annotatedSuperclass.getType())) { - annotatedSuperclass = null; - } - - AnnotatedType[] allAnnotatedInterfaces; - try { - allAnnotatedInterfaces = javaClass.getAnnotatedInterfaces(); - } catch (MalformedParameterizedTypeException | TypeNotPresentException | LinkageError t) { - /* - * Loading annotated interfaces can fail due to missing types. Ignore the exception and - * return an empty array. - */ - allAnnotatedInterfaces = new AnnotatedType[0]; - } - - AnnotatedType[] annotatedInterfaces = Arrays.stream(allAnnotatedInterfaces) - .filter(ai -> isTypeAllowed(ai.getType())).toArray(AnnotatedType[]::new); - AnnotatedType[] cachedAnnotatedInterfaces = annotatedInterfacesMap.computeIfAbsent( - new AnnotatedInterfacesEncodingKey(annotatedInterfaces), k -> annotatedInterfaces); - hub.setAnnotatedSuperInfo(AnnotatedSuperInfo.factory(annotatedSuperclass, cachedAnnotatedInterfaces)); - } - - private boolean isTypeAllowed(Type t) { - if (t instanceof Class) { - Optional resolved = metaAccess.optionalLookupJavaType((Class) t); - return resolved.isPresent() && hostVM.platformSupported(universe, resolved.get()); - } - return true; - } - - class InterfacesEncodingKey { - final AnalysisType[] aInterfaces; - - InterfacesEncodingKey(AnalysisType[] aInterfaces) { - this.aInterfaces = aInterfaces; - } - - DynamicHub[] createHubs() { - SVMHost svmHost = (SVMHost) hostVM; - DynamicHub[] hubs = new DynamicHub[aInterfaces.length]; - for (int i = 0; i < hubs.length; i++) { - hubs[i] = svmHost.dynamicHub(aInterfaces[i]); - } - return hubs; - } - - @Override - public boolean equals(Object obj) { - return obj instanceof InterfacesEncodingKey && Arrays.equals(aInterfaces, ((InterfacesEncodingKey) obj).aInterfaces); - } - - @Override - public int hashCode() { - return Arrays.hashCode(aInterfaces); - } - } - - /** - * Fill array returned by Class.getInterfaces(). - */ - private void fillInterfaces(AnalysisType type, DynamicHub hub) { - SVMHost svmHost = (SVMHost) hostVM; - - AnalysisType[] aInterfaces = type.getInterfaces(); - if (aInterfaces.length == 0) { - hub.setInterfacesEncoding(null); - } else if (aInterfaces.length == 1) { - hub.setInterfacesEncoding(svmHost.dynamicHub(aInterfaces[0])); - } else { - /* - * Many interfaces arrays are the same, e.g., all arrays implement the same two - * interfaces. We want to avoid duplicate arrays with the same content in the native - * image heap. - */ - hub.setInterfacesEncoding(interfacesEncodings.computeIfAbsent(new InterfacesEncodingKey(aInterfaces), InterfacesEncodingKey::createHubs)); - } - } - private void scanHub(ObjectScanner objectScanner, AnalysisType type) { SVMHost svmHost = (SVMHost) hostVM; JavaConstant hubConstant = SubstrateObjectConstant.forObject(svmHost.dynamicHub(type)); @@ -542,7 +210,7 @@ private List extractAnnotationTypes(AnalysisField field, UnknownOb " | annotation type: " + annotationType; assert declaredType.isAssignableFrom(aAnnotationType) : "Annotation type must be a subtype of the declared type: field: " + field + " | declared type: " + declaredType + " | annotation type: " + annotationType; - assert aAnnotationType.isArray() || (aAnnotationType.isInstanceClass() && !Modifier.isAbstract(aAnnotationType.getModifiers())) : "Annotation type failure: field: " + field + + assert aAnnotationType.isArray() || (aAnnotationType.isInstanceClass() && !Modifier.isAbstract(aAnnotationType.getModifiers())) : "Annotation type cannot be abstract: field: " + field + " | annotation type " + aAnnotationType; aAnnotationTypes.add(aAnnotationType); @@ -596,75 +264,6 @@ private void handleUnknownObjectField(AnalysisField aField, AnalysisType... decl } } - private static Set filterUsedAnnotation(Set used, Annotation[] rest) { - if (rest == null) { - return null; - } - - Set restUsed = new HashSet<>(); - for (Annotation a : rest) { - if (used.contains(a)) { - restUsed.add(a); - } - } - return restUsed; - } - - public static Object encodeAnnotations(AnalysisMetaAccess metaAccess, Annotation[] allAnnotations, Annotation[] declaredAnnotations, Object oldEncoding) { - Object newEncoding; - if (allAnnotations.length == 0 && declaredAnnotations.length == 0) { - newEncoding = null; - } else { - Set all = new HashSet<>(); - Collections.addAll(all, allAnnotations); - Collections.addAll(all, declaredAnnotations); - final Set usedAnnotations = all.stream() - .filter(a -> { - try { - AnalysisType annotationClass = metaAccess.lookupJavaType(a.getClass()); - return isAnnotationUsed(annotationClass); - } catch (TypeNotFoundError e) { - /* - * Silently ignore the annotation if its type was not discovered - * by the static analysis. - */ - return false; - } - }).collect(Collectors.toSet()); - Set usedDeclared = filterUsedAnnotation(usedAnnotations, declaredAnnotations); - newEncoding = usedAnnotations.size() == 0 - ? null - : AnnotationsEncoding.encodeAnnotations(usedAnnotations, usedDeclared); - } - - /* - * Return newEncoding only if the value is different from oldEncoding. Without this guard, - * for tests that do runtime compilation, the field appears as being continuously updated - * during BigBang.checkObjectGraph. - */ - if (oldEncoding != null && oldEncoding.equals(newEncoding)) { - return oldEncoding; - } else { - return newEncoding; - } - } - - /** - * We only want annotations in the native image heap that are "used" at run time. In our case, - * "used" means that the annotation interface is used at least in a type check. This leaves one - * case where Substrate VM behaves differently than a normal Java VM: When you just query the - * number of annotations on a class, then we might return a lower number. - */ - private static boolean isAnnotationUsed(AnalysisType annotationType) { - if (annotationType.isReachable()) { - return true; - } - assert annotationType.getInterfaces().length == 1 : annotationType; - - AnalysisType annotationInterfaceType = annotationType.getInterfaces()[0]; - return annotationInterfaceType.isReachable(); - } - public static ResolvedJavaType toWrappedType(ResolvedJavaType type) { if (type instanceof AnalysisType) { return ((AnalysisType) type).getWrappedWithoutResolve(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/ConstantAnnotationMarkerSubstitutionType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/ConstantAnnotationMarkerSubstitutionType.java index 33f9dd3579dc..a684606fa4d9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/ConstantAnnotationMarkerSubstitutionType.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/ConstantAnnotationMarkerSubstitutionType.java @@ -28,7 +28,7 @@ import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; -import com.oracle.svm.hosted.c.GraalAccess; +import com.oracle.graal.pointsto.util.GraalAccess; import jdk.vm.ci.meta.Assumptions; import jdk.vm.ci.meta.JavaConstant; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionMethod.java index 7f3dd9c347cd..3a1691dc10fa 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionMethod.java @@ -32,7 +32,7 @@ import com.oracle.graal.pointsto.infrastructure.GraphProvider; import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; -import com.oracle.svm.hosted.c.GraalAccess; +import com.oracle.graal.pointsto.util.GraalAccess; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantPool; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionType.java index 6cbee9e255ac..fcff66ac0f29 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionType.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionType.java @@ -31,7 +31,7 @@ import java.util.Map; import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; -import com.oracle.svm.hosted.c.GraalAccess; +import com.oracle.graal.pointsto.util.GraalAccess; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.Assumptions.AssumptionResult; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java index b13d562b0b80..b32d97e584a0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java @@ -258,10 +258,10 @@ protected void verify() { Class substrateTargetArch = ImageSingletons.lookup(SubstrateTargetDescription.class).arch.getClass(); Class guessed = guessArchitecture(compilerInfo.targetArch); if (guessed == null) { - UserError.abort("Native toolchain (%s) has no matching native-image target architecture.", compilerInfo.targetArch); + UserError.abort("Linux native toolchain (%s) has no matching native-image target architecture.", compilerInfo.targetArch); } if (guessed != substrateTargetArch) { - UserError.abort("Native toolchain (%s) implies native-image target architecture %s but configured native-image target architecture is %s.", + UserError.abort("Linux native toolchain (%s) implies native-image target architecture %s but configured native-image target architecture is %s.", compilerInfo.targetArch, guessed, substrateTargetArch); } } @@ -302,12 +302,23 @@ protected CompilerInfo createCompilerInfo(Path compilerPath, Scanner scanner) { @Override protected void verify() { - if (guessArchitecture(compilerInfo.targetArch) != AMD64.class) { - UserError.abort("Native-image building on Darwin currently only supports target architecture: %s (%s unsupported)", - AMD64.class.getSimpleName(), compilerInfo.targetArch); + Class substrateTargetArch = ImageSingletons.lookup(SubstrateTargetDescription.class).arch.getClass(); + Class guessed = guessArchitecture(compilerInfo.targetArch); + if (guessed == null) { + UserError.abort("Darwin native toolchain (%s) has no matching native-image target architecture.", compilerInfo.targetArch); + } + if (guessed != substrateTargetArch) { + UserError.abort("Darwin native toolchain (%s) implies native-image target architecture %s but configured native-image target architecture is %s.", + compilerInfo.targetArch, guessed, substrateTargetArch); } } + @Override + protected List compileStrictOptions() { + List strictOptions = new ArrayList<>(super.compileStrictOptions()); + strictOptions.add("-Wno-tautological-compare"); + return strictOptions; + } } protected InputStream getCompilerErrorStream(Process compilingProcess) { @@ -421,6 +432,7 @@ protected static Class guessArchitecture(String archStr) case "x64": /* Windows notation */ return AMD64.class; case "aarch64": + case "arm64": /* Darwin notation */ return AArch64.class; case "i686": case "80x86": /* Windows notation */ diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/info/InfoTreeBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/info/InfoTreeBuilder.java index 2e4518a42d8d..f4665899d460 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/info/InfoTreeBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/info/InfoTreeBuilder.java @@ -56,10 +56,10 @@ import com.oracle.graal.pointsto.infrastructure.WrappedElement; import com.oracle.graal.pointsto.infrastructure.WrappedJavaType; import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.c.CTypedef; import com.oracle.svm.core.c.struct.PinnedObjectField; import com.oracle.svm.hosted.c.BuiltinDirectives; -import com.oracle.svm.hosted.c.GraalAccess; import com.oracle.svm.hosted.c.NativeCodeContext; import com.oracle.svm.hosted.c.NativeLibraries; import com.oracle.svm.hosted.c.info.AccessorInfo.AccessorKind; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java index deda2c6fc758..9060a15a291a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java @@ -44,6 +44,7 @@ import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.util.Providers; +import org.graalvm.nativeimage.c.function.CFunctionPointer; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; @@ -340,7 +341,7 @@ private static ClassInitializationInfo buildRuntimeInitializationInfo(FeatureImp /* Synthesize a VerifyError to be thrown at run time. */ AnalysisMethod throwVerifyError = access.getMetaAccess().lookupJavaMethod(ExceptionSynthesizer.throwExceptionMethod(VerifyError.class)); access.registerAsCompiled(throwVerifyError); - return new ClassInitializationInfo(MethodPointer.factory(throwVerifyError)); + return new ClassInitializationInfo(new MethodPointer(throwVerifyError)); } catch (Throwable t) { /* * All other linking errors will be reported as NoClassDefFoundError when initialization @@ -354,11 +355,13 @@ private static ClassInitializationInfo buildRuntimeInitializationInfo(FeatureImp * information. */ assert type.isLinked(); + CFunctionPointer classInitializerFunction = null; AnalysisMethod classInitializer = type.getClassInitializer(); if (classInitializer != null) { assert classInitializer.getCode() != null; access.registerAsCompiled(classInitializer); + classInitializerFunction = new MethodPointer(classInitializer); } - return new ClassInitializationInfo(MethodPointer.factory(classInitializer)); + return new ClassInitializationInfo(classInitializerFunction); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ConfigurableClassInitialization.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ConfigurableClassInitialization.java index 9572bdbd759d..96d6211b6298 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ConfigurableClassInitialization.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ConfigurableClassInitialization.java @@ -46,13 +46,13 @@ import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.graal.pointsto.reports.ReportUtils; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ImageClassLoader; import com.oracle.svm.hosted.NativeImageOptions; -import com.oracle.svm.hosted.c.GraalAccess; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaType; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/EarlyClassInitializerAnalysis.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/EarlyClassInitializerAnalysis.java index 1aa15f0fc94b..4e69489f4c9a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/EarlyClassInitializerAnalysis.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/EarlyClassInitializerAnalysis.java @@ -54,14 +54,14 @@ import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.phases.util.Providers; +import com.oracle.graal.pointsto.phases.NoClassInitializationPlugin; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode; import com.oracle.svm.core.graal.thread.VMThreadLocalAccess; import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.c.GraalAccess; import com.oracle.svm.hosted.phases.EarlyConstantFoldLoadFieldPlugin; -import com.oracle.svm.hosted.phases.NoClassInitializationPlugin; import com.oracle.svm.hosted.snippets.ReflectionPlugins; import com.oracle.svm.hosted.snippets.SubstrateGraphBuilderPlugins; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubSupport.java index c6eb898ece3b..90a80cb80adf 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubSupport.java @@ -110,7 +110,7 @@ public AnalysisMethod registerJavaStubForMethod(AnalysisMethod method) { if (value == null) { assert !bb.getUniverse().sealed(); AnalysisMethod nativeStub = registerStubForMethod(method, () -> CEntryPointData.create(method)); - CFunctionPointer nativeStubAddress = MethodPointer.factory(nativeStub); + CFunctionPointer nativeStubAddress = new MethodPointer(nativeStub); String stubName = SubstrateUtil.uniqueShortName(method); ResolvedJavaType holderClass = bb.getMetaAccess().lookupJavaType(IsolateLeaveStub.class).getWrapped(); CEntryPointJavaCallStubMethod stub = new CEntryPointJavaCallStubMethod(method.getWrapped(), stubName, holderClass, nativeStubAddress); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointLiteralFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointLiteralFeature.java index c5fd686aad87..1e69f5e974f8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointLiteralFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointLiteralFeature.java @@ -81,7 +81,7 @@ public Object apply(Object source) { * Only during compilation and native image writing, we do the actual * replacement. */ - return MethodPointer.factory(hStub); + return new MethodPointer(hStub); } } return source; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedPatcher.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedPatcher.java index 2dc76df0eaef..862f2e12c3e1 100755 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedPatcher.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedPatcher.java @@ -34,11 +34,19 @@ public interface HostedPatcher { /** * Create relocation for the binary file. + * + * @param ref value instruction sequence should refer to + * @param relocs buffer of added relocation site information + * @param compStart codecache-relative starting position this method's machine code */ void relocate(Reference ref, RelocatableBuffer relocs, int compStart); /** * Patch the code buffer. + * + * @param compStart codecache-relative starting position this method's machine code + * @param relative pc-relative offset + * @param code machine code generated for this method */ - void patch(int codePos, int relative, byte[] code); + void patch(int compStart, int relative, byte[] code); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/aarch64/AArch64HostedPatcher.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/aarch64/AArch64HostedPatcher.java index fc2e551e4725..90f4d6218115 100755 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/aarch64/AArch64HostedPatcher.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/aarch64/AArch64HostedPatcher.java @@ -96,8 +96,9 @@ public void relocate(Reference ref, RelocatableBuffer relocs, int compStart) { @Uninterruptible(reason = ".") @Override - public void patch(int codePos, int relative, byte[] code) { - annotation.patch(codePos, relative, code); + public void patch(int compStart, int relative, byte[] code) { + long startAddress = ((long) compStart) + annotation.instructionPosition; + annotation.patch(startAddress, relative, code); } @Override @@ -118,7 +119,7 @@ class AdrpLdrMacroInstructionHostedPatcher extends CompilationResult.CodeAnnotat public void relocate(Reference ref, RelocatableBuffer relocs, int compStart) { int siteOffset = compStart + macroInstruction.instructionPosition; - relocs.addRelocationWithAddend(siteOffset, RelocationKind.AARCH64_R_AARCH64_ADR_PREL_PG_HI21, Long.valueOf(0), ref); + relocs.addRelocationWithoutAddend(siteOffset, RelocationKind.AARCH64_R_AARCH64_ADR_PREL_PG_HI21, ref); siteOffset += 4; RelocationKind secondRelocation; switch (macroInstruction.srcSize) { @@ -140,13 +141,14 @@ public void relocate(Reference ref, RelocatableBuffer relocs, int compStart) { default: throw VMError.shouldNotReachHere("Unknown macro instruction src size of " + macroInstruction.srcSize); } - relocs.addRelocationWithAddend(siteOffset, secondRelocation, Long.valueOf(0), ref); + relocs.addRelocationWithoutAddend(siteOffset, secondRelocation, ref); } @Uninterruptible(reason = ".") @Override - public void patch(int codePos, int relative, byte[] code) { - macroInstruction.patch(codePos, relative, code); + public void patch(int compStart, int relative, byte[] code) { + long startAddress = ((long) compStart) + macroInstruction.instructionPosition; + macroInstruction.patch(startAddress, relative, code); } @Override @@ -168,15 +170,16 @@ class AdrpAddMacroInstructionHostedPatcher extends CompilationResult.CodeAnnotat public void relocate(Reference ref, RelocatableBuffer relocs, int compStart) { int siteOffset = compStart + macroInstruction.instructionPosition; - relocs.addRelocationWithAddend(siteOffset, RelocationKind.AARCH64_R_AARCH64_ADR_PREL_PG_HI21, Long.valueOf(0), ref); + relocs.addRelocationWithoutAddend(siteOffset, RelocationKind.AARCH64_R_AARCH64_ADR_PREL_PG_HI21, ref); siteOffset += 4; - relocs.addRelocationWithAddend(siteOffset, RelocationKind.AARCH64_R_AARCH64_ADD_ABS_LO12_NC, Long.valueOf(0), ref); + relocs.addRelocationWithoutAddend(siteOffset, RelocationKind.AARCH64_R_AARCH64_ADD_ABS_LO12_NC, ref); } @Uninterruptible(reason = ".") @Override - public void patch(int codePos, int relative, byte[] code) { - macroInstruction.patch(codePos, relative, code); + public void patch(int compStart, int relative, byte[] code) { + long startAddress = ((long) compStart) + macroInstruction.instructionPosition; + macroInstruction.patch(startAddress, relative, code); } @Override @@ -228,9 +231,9 @@ public void relocate(Reference ref, RelocatableBuffer relocs, int compStart) { continue; } if (i == lastMovIndex) { - relocs.addRelocationWithAddend(siteOffset, relocations[i], Long.valueOf(0), ref); + relocs.addRelocationWithoutAddend(siteOffset, relocations[i], ref); } else { - relocs.addRelocationWithAddend(siteOffset, noCheckRelocations[i], Long.valueOf(0), ref); + relocs.addRelocationWithoutAddend(siteOffset, noCheckRelocations[i], ref); } siteOffset = siteOffset + 4; } @@ -241,8 +244,9 @@ public void relocate(Reference ref, RelocatableBuffer relocs, int compStart) { @Uninterruptible(reason = ".") @Override - public void patch(int codePos, int relative, byte[] code) { - annotation.patch(codePos, relative, code); + public void patch(int compStart, int relative, byte[] code) { + /* Patching a move sequence would hardcode an absolute value, not a pc-relative value. */ + throw VMError.shouldNotReachHere(); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/amd64/AMD64HostedPatcher.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/amd64/AMD64HostedPatcher.java index 270ac190569b..6d069ba7859d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/amd64/AMD64HostedPatcher.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/amd64/AMD64HostedPatcher.java @@ -86,7 +86,7 @@ public AMD64HostedPatcher(OperandDataAnnotation annotation) { @Uninterruptible(reason = ".") @Override - public void patch(int codePos, int relative, byte[] code) { + public void patch(int compStart, int relative, byte[] code) { int curValue = relative - (annotation.nextInstructionPosition - annotation.instructionPosition); for (int i = 0; i < annotation.operandSize; i++) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/ConfigurationParserUtils.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/ConfigurationParserUtils.java index f5e2a1b5d56f..193c309a935a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/ConfigurationParserUtils.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/ConfigurationParserUtils.java @@ -24,7 +24,7 @@ */ package com.oracle.svm.hosted.config; -import static com.oracle.svm.core.SubstrateOptions.PrintFlags; +import static com.oracle.svm.common.option.CommonOptions.PrintFlags; import java.io.IOException; import java.io.InputStreamReader; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dashboard/PointsToJsonObject.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dashboard/PointsToJsonObject.java index d843b675b506..60de2504feb7 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dashboard/PointsToJsonObject.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dashboard/PointsToJsonObject.java @@ -36,11 +36,11 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import com.oracle.graal.pointsto.BigBang; import org.graalvm.graphio.GraphOutput; import org.graalvm.graphio.GraphStructure; import org.graalvm.nativeimage.hosted.Feature.OnAnalysisExitAccess; +import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.flow.ActualParameterTypeFlow; import com.oracle.graal.pointsto.flow.ActualReturnTypeFlow; @@ -596,7 +596,7 @@ private WrapperClazz(Class wrappedClass, int inputs, int uses, String name) { */ private void serializeMethods(BigBang bb) { for (AnalysisMethod method : bb.getUniverse().getMethods()) { - serializeMethod(new AnalysisWrapper(method.getClass(), method)); + serializeMethod(bb, new AnalysisWrapper(method.getClass(), method)); } } @@ -605,7 +605,7 @@ private void serializeMethods(BigBang bb) { * * @param methodWrapper wrapped AnalysisMethod whose type flows to serialize */ - private void serializeMethod(AnalysisWrapper methodWrapper) { + private void serializeMethod(BigBang bb, AnalysisWrapper methodWrapper) { assert !known.get(methodWrapper.id); known.set(methodWrapper.id); flows.set(methodWrapper.id, methodWrapper); @@ -622,7 +622,7 @@ private void serializeMethod(AnalysisWrapper methodWrapper) { } // Serialize this type flow to a JSON object, add it to the node index. - serializeTypeFlow(flow); + serializeTypeFlow(bb, flow); } } @@ -638,7 +638,7 @@ private void serializeMethod(AnalysisWrapper methodWrapper) { * * @param flow TypeFlow to serialize */ - private void serializeTypeFlow(TypeFlow flow) { + private void serializeTypeFlow(BigBang bb, TypeFlow flow) { int flowId = flow.id(); if (known.get(flowId)) { @@ -661,13 +661,13 @@ private void serializeTypeFlow(TypeFlow flow) { flowWrapper.calleeNames.add(callee.getQualifiedName()); } } else if (flow instanceof NewInstanceTypeFlow || flow instanceof DynamicNewInstanceTypeFlow) { - flowWrapper.types = serializeTypeState(flow.getState()); + flowWrapper.types = serializeTypeState(bb, flow.getState()); } else if (flow instanceof LoadFieldTypeFlow.LoadInstanceFieldTypeFlow || flow instanceof LoadFieldTypeFlow.LoadStaticFieldTypeFlow) { LoadFieldTypeFlow loadFlow = (LoadFieldTypeFlow) flow; flowWrapper.qualifiedName = fieldName(loadFlow.field()); } else if (flow instanceof StoreFieldTypeFlow.StoreInstanceFieldTypeFlow || flow instanceof StoreFieldTypeFlow.StoreStaticFieldTypeFlow) { TypeState typeState = flow.getState(); - flowWrapper.types = serializeTypeState(typeState); + flowWrapper.types = serializeTypeState(bb, typeState); StoreFieldTypeFlow storeFlow = (StoreFieldTypeFlow) flow; flowWrapper.qualifiedName = fieldName(storeFlow.field()); } else if (flow instanceof FieldTypeFlow) { @@ -678,8 +678,8 @@ private void serializeTypeFlow(TypeFlow flow) { } // Set inputs and uses for this node. - collectInputs(flow, flowWrapper.inputs); - collectUses(flow, flowWrapper.uses); + collectInputs(bb, flow, flowWrapper.inputs); + collectUses(bb, flow, flowWrapper.uses); } /** @@ -775,20 +775,20 @@ private static String getCodeLocation(TypeFlow flow) { * @param flow TypeFlow who's inputs and observees to collect * @param targetList target array for input use and observee IDs to */ - private void collectInputs(TypeFlow flow, Map targetList) { + private void collectInputs(BigBang bb, TypeFlow flow, Map targetList) { for (Object input : flow.getInputs()) { TypeFlow inputFlow = (TypeFlow) input; addUnique(targetList, inputFlow.id()); // Indirect recursive call. Call with methodId = -1 to indicate that, at this point, // we don't know the method ID of the parent methods of the input flows. - serializeTypeFlow(inputFlow); + serializeTypeFlow(bb, inputFlow); } for (Object observee : flow.getObservees()) { TypeFlow observeeFlow = (TypeFlow) observee; addUnique(targetList, observeeFlow.id()); // Indirect recursive call. Call with methodId = -1 to indicate that, at this point, // we don't know the method ID of the parent methods of the observee flows. - serializeTypeFlow(observeeFlow); + serializeTypeFlow(bb, observeeFlow); } } @@ -800,20 +800,20 @@ private void collectInputs(TypeFlow flow, Map targetList) { * @param flow TypeFlow who's uses and observers to collect * @param targetList target list for adding use and observer IDs to */ - private void collectUses(TypeFlow flow, Map targetList) { + private void collectUses(BigBang bb, TypeFlow flow, Map targetList) { for (Object use : flow.getUses()) { TypeFlow useFlow = (TypeFlow) use; addUnique(targetList, useFlow.id()); // Indirect recursive call. Call with methodId = -1 to indicate that, at this point, // we don't know the method ID of the parent methods of the use flows. - serializeTypeFlow(useFlow); + serializeTypeFlow(bb, useFlow); } for (Object observer : flow.getObservers()) { TypeFlow observerFlow = (TypeFlow) observer; addUnique(targetList, observerFlow.id()); // Indirect recursive call. Call with methodId = -1 to indicate that, at this point, // we don't know the method ID of the parent methods of the observer flows. - serializeTypeFlow(observerFlow); + serializeTypeFlow(bb, observerFlow); } } @@ -834,9 +834,9 @@ private static void addUnique(Map list, T element) { * @param typeState the TypeState to be serialized. * @return a list of the formatted class names of the classes included in the given TypeState. */ - private static ArrayList serializeTypeState(TypeState typeState) { + private static ArrayList serializeTypeState(BigBang bb, TypeState typeState) { ArrayList types = new ArrayList<>(); - for (AnalysisType type : typeState.types()) { + for (AnalysisType type : typeState.types(bb)) { types.add(type.toJavaName()); } return types; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java index 27d4aebbb735..d0e9d6cbb00a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java @@ -26,6 +26,7 @@ import java.nio.ByteBuffer; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -103,7 +104,7 @@ public void layoutMethods(DebugContext debug, String imageName, BigBang bb, Fork codeCacheSize = NumUtil.roundUp(codeCacheSize + compilation.getTargetCodeSize(), SubstrateOptions.codeAlignment()); } - buildRuntimeMetadata(MethodPointer.factory(firstMethod), WordFactory.unsigned(codeCacheSize)); + buildRuntimeMetadata(new MethodPointer(firstMethod), WordFactory.unsigned(codeCacheSize)); } } @@ -157,7 +158,8 @@ public void patchMethods(DebugContext debug, RelocatableBuffer relocs, ObjectFil ByteBuffer targetCode = null; for (CodeAnnotation codeAnnotation : compilation.getCodeAnnotations()) { if (codeAnnotation instanceof HostedPatcher) { - patches.put(codeAnnotation.getPosition(), (HostedPatcher) codeAnnotation); + HostedPatcher priorValue = patches.put(codeAnnotation.getPosition(), (HostedPatcher) codeAnnotation); + VMError.guarantee(priorValue == null, "Registering two patchers for same position."); } else if (codeAnnotation instanceof HostedImageHeapConstantPatch) { HostedImageHeapConstantPatch patch = (HostedImageHeapConstantPatch) codeAnnotation; @@ -174,6 +176,8 @@ public void patchMethods(DebugContext debug, RelocatableBuffer relocs, ObjectFil targetCode.putInt(patch.getPosition(), (int) newValue); } } + int patchesHandled = 0; + HashSet patchedOffsets = new HashSet<>(); // ... patch direct call sites. for (Infopoint infopoint : compilation.getInfopoints()) { if (infopoint instanceof Call && ((Call) infopoint).direct) { @@ -188,7 +192,10 @@ public void patchMethods(DebugContext debug, RelocatableBuffer relocs, ObjectFil // Patch a PC-relative call. // This code handles the case of section-local calls only. int pcDisplacement = callTargetStart - (compStart + call.pcOffset); - patches.get(call.pcOffset).patch(call.pcOffset, pcDisplacement, compilation.getTargetCode()); + patches.get(call.pcOffset).patch(compStart, pcDisplacement, compilation.getTargetCode()); + boolean noPriorMatch = patchedOffsets.add(call.pcOffset); + VMError.guarantee(noPriorMatch, "Patching same offset twice."); + patchesHandled++; } } for (DataPatch dataPatch : compilation.getDataPatches()) { @@ -198,7 +205,11 @@ public void patchMethods(DebugContext debug, RelocatableBuffer relocs, ObjectFil * read-only (.rodata) section. */ patches.get(dataPatch.pcOffset).relocate(ref, relocs, compStart); + boolean noPriorMatch = patchedOffsets.add(dataPatch.pcOffset); + VMError.guarantee(noPriorMatch, "Patching same offset twice."); + patchesHandled++; } + VMError.guarantee(patchesHandled == patches.size(), "Not all patches applied."); try (DebugContext.Scope ds = debug.scope("After Patching", method.asJavaMethod())) { debug.dump(DebugContext.BASIC_LEVEL, compilation, "After patching"); } catch (Throwable e) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java index 18d4f292a131..7232cb946d82 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java @@ -59,6 +59,7 @@ import org.graalvm.compiler.debug.Indent; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.c.function.CFunctionPointer; +import org.graalvm.nativeimage.hosted.Feature; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -77,9 +78,11 @@ import com.oracle.svm.core.BuildArtifacts; import com.oracle.svm.core.BuildArtifacts.ArtifactType; import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.InvalidMethodPointerHandler; import com.oracle.svm.core.Isolates; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; +import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.core.c.CConst; import com.oracle.svm.core.c.CGlobalDataImpl; import com.oracle.svm.core.c.CHeader; @@ -96,6 +99,7 @@ import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.core.util.UserError; +import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.NativeImageOptions; import com.oracle.svm.hosted.c.CGlobalDataFeature; import com.oracle.svm.hosted.c.NativeLibraries; @@ -390,7 +394,7 @@ private ObjectFile.Symbol defineRelocationForSymbol(String name, long position) } ProgbitsSectionImpl baseSectionImpl = (ProgbitsSectionImpl) rwDataSection.getImpl(); int offsetInSection = Math.toIntExact(RWDATA_CGLOBALS_PARTITION_OFFSET + position); - baseSectionImpl.markRelocationSite(offsetInSection, wordSize == 8 ? RelocationKind.DIRECT_8 : RelocationKind.DIRECT_4, name, false, 0L); + baseSectionImpl.markRelocationSite(offsetInSection, wordSize == 8 ? RelocationKind.DIRECT_8 : RelocationKind.DIRECT_4, name, 0L); return symbol; } @@ -449,9 +453,8 @@ public void build(String imageName, DebugContext debug) { /* * If we constructed debug info give the object file a chance to install it */ - if (SubstrateOptions.GenerateDebugInfo.getValue(HostedOptionValues.singleton()) > 0) { + if (SubstrateOptions.GenerateDebugInfo.getValue(HostedOptionValues.singleton()) > 0 && !SubstrateOptions.useLLVMBackend()) { try (Timer.StopTimer t = new Timer(imageName, "dbginfo").start()) { - ImageSingletons.add(SourceManager.class, new SourceManager()); DebugInfoProvider provider = new NativeImageDebugInfoProvider(debug, codeCache, heap); objectFile.installDebugInfo(provider); } @@ -564,14 +567,19 @@ private static boolean checkEmbeddedOffset(ProgbitsSectionImpl sectionImpl, fina return true; } - private static void markFunctionRelocationSite(final ProgbitsSectionImpl sectionImpl, final int offset, final RelocatableBuffer.Info info) { + private void markFunctionRelocationSite(final ProgbitsSectionImpl sectionImpl, final int offset, final RelocatableBuffer.Info info) { assert info.getTargetObject() instanceof CFunctionPointer : "Wrong type for FunctionPointer relocation: " + info.getTargetObject().toString(); final int functionPointerRelocationSize = 8; assert info.getRelocationSize() == functionPointerRelocationSize : "Function relocation: " + info.getRelocationSize() + " should be " + functionPointerRelocationSize + " bytes."; // References to functions are via relocations to the symbol for the function. - ResolvedJavaMethod method = ((MethodPointer) info.getTargetObject()).getMethod(); + MethodPointer methodPointer = (MethodPointer) info.getTargetObject(); + ResolvedJavaMethod method = methodPointer.getMethod(); + HostedMethod target = (method instanceof HostedMethod) ? (HostedMethod) method : heap.getUniverse().lookup(method); + if (!target.isCompiled()) { + target = metaAccess.lookupJavaMethod(InvalidMethodPointerHandler.METHOD_POINTER_NOT_COMPILED_HANDLER_METHOD); + } // A reference to a method. Mark the relocation site using the symbol name. - sectionImpl.markRelocationSite(offset, RelocationKind.getDirect(functionPointerRelocationSize), localSymbolNameForMethod(method), false, 0L); + sectionImpl.markRelocationSite(offset, RelocationKind.getDirect(functionPointerRelocationSize), localSymbolNameForMethod(target), 0L); } private static boolean isAddendAligned(Architecture arch, long addend, RelocationKind kind) { @@ -604,9 +612,8 @@ private void markDataRelocationSite(ProgbitsSectionImpl sectionImpl, int offset, assert targetObjectInfo != null; String targetSectionName = heapSection.getName(); long address = targetObjectInfo.getAddress(); - long relocationInfoAddend = info.hasExplicitAddend() ? info.getExplicitAddend() : 0L; - long relocationAddend = address + relocationInfoAddend; - sectionImpl.markRelocationSite(offset, info.getRelocationKind(), targetSectionName, false, relocationAddend); + long relocationAddend = address + info.getAddend(); + sectionImpl.markRelocationSite(offset, info.getRelocationKind(), targetSectionName, relocationAddend); } private void markDataRelocationSiteFromText(RelocatableBuffer buffer, final ProgbitsSectionImpl sectionImpl, final int offset, final Info info) { @@ -615,23 +622,23 @@ private void markDataRelocationSiteFromText(RelocatableBuffer buffer, final Prog info.getRelocationSize(); Object target = info.getTargetObject(); if (target instanceof DataSectionReference) { - long addend = ((DataSectionReference) target).getOffset() - info.getExplicitAddend(); + long addend = ((DataSectionReference) target).getOffset() - info.getAddend(); assert isAddendAligned(arch, addend, info.getRelocationKind()) : "improper addend alignment"; - sectionImpl.markRelocationSite(offset, info.getRelocationKind(), roDataSection.getName(), false, addend); + sectionImpl.markRelocationSite(offset, info.getRelocationKind(), roDataSection.getName(), addend); } else if (target instanceof CGlobalDataReference) { CGlobalDataReference ref = (CGlobalDataReference) target; CGlobalDataInfo dataInfo = ref.getDataInfo(); CGlobalDataImpl data = dataInfo.getData(); - long addend = RWDATA_CGLOBALS_PARTITION_OFFSET + dataInfo.getOffset() - info.getExplicitAddend(); + long addend = RWDATA_CGLOBALS_PARTITION_OFFSET + dataInfo.getOffset() - info.getAddend(); assert isAddendAligned(arch, addend, info.getRelocationKind()) : "improper addend alignment"; - sectionImpl.markRelocationSite(offset, info.getRelocationKind(), rwDataSection.getName(), false, addend); + sectionImpl.markRelocationSite(offset, info.getRelocationKind(), rwDataSection.getName(), addend); if (dataInfo.isSymbolReference()) { // create relocation for referenced symbol if (objectFile.getSymbolTable().getSymbol(data.symbolName) == null) { objectFile.createUndefinedSymbol(data.symbolName, 0, true); } ProgbitsSectionImpl baseSectionImpl = (ProgbitsSectionImpl) rwDataSection.getImpl(); int offsetInSection = Math.toIntExact(RWDATA_CGLOBALS_PARTITION_OFFSET + dataInfo.getOffset()); - baseSectionImpl.markRelocationSite(offsetInSection, RelocationKind.getDirect(wordSize), data.symbolName, false, 0L); + baseSectionImpl.markRelocationSite(offsetInSection, RelocationKind.getDirect(wordSize), data.symbolName, 0L); } } else if (target instanceof ConstantReference) { // Direct object reference in code that must be patched (not a linker relocation) @@ -675,9 +682,14 @@ private void markDataRelocationSiteFromText(RelocatableBuffer buffer, final Prog // validating patched value does not overflow operand switch (info.getRelocationKind()) { case AARCH64_R_MOVW_UABS_G0: + assert (targetValue & 0xFFFF_FFFF_FFFF_0000L) == 0 : "value to patch does not fit"; + break; case AARCH64_R_MOVW_UABS_G1: + assert (targetValue & 0xFFFF_FFFF_0000_0000L) == 0 : "value to patch does not fit"; + break; case AARCH64_R_MOVW_UABS_G2: - assert (patchValue & 0xFFFF) == patchValue : "value to patch does not fit"; + assert (targetValue & 0xFFFF_0000_0000_0000L) == 0 : "value to patch does not fit"; + break; } int originalInst = bufferBytes.getInt(offset); int newInst = AArch64Assembler.PatcherUtil.patchMov(originalInst, patchValue); @@ -951,3 +963,12 @@ protected NativeTextSectionImpl(RelocatableBuffer relocatableBuffer, ObjectFile protected final NativeImageCodeCache codeCache; } } + +@AutomaticFeature +final class MethodPointerInvalidHandlerFeature implements Feature { + @Override + public void beforeAnalysis(BeforeAnalysisAccess a) { + FeatureImpl.BeforeAnalysisAccessImpl access = (FeatureImpl.BeforeAnalysisAccessImpl) a; + access.registerAsCompiled(InvalidMethodPointerHandler.METHOD_POINTER_NOT_COMPILED_HANDLER_METHOD); + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java index 8f43ebfeb1d8..9a68d5596432 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java @@ -214,7 +214,7 @@ public int getAlignedConstantsSize() { public void buildRuntimeMetadata(CFunctionPointer firstMethod, UnsignedWord codeSize) { // Build run-time metadata. - FrameInfoCustomization frameInfoCustomization = new FrameInfoCustomization(); + HostedFrameInfoCustomization frameInfoCustomization = new HostedFrameInfoCustomization(); CodeInfoEncoder codeInfoEncoder = new CodeInfoEncoder(frameInfoCustomization); for (Entry entry : compilations.entrySet()) { final HostedMethod method = entry.getKey(); @@ -435,7 +435,7 @@ public void printCompilationResults() { } } - private static class FrameInfoCustomization extends FrameInfoEncoder.NamesFromMethod { + private static class HostedFrameInfoCustomization extends FrameInfoEncoder.SourceFieldsFromMethod { int numDeoptEntryPoints; int numDuringCallEntryPoints; @@ -447,12 +447,12 @@ protected Class getDeclaringJavaClass(ResolvedJavaMethod method) { } @Override - protected boolean shouldStoreMethod() { + protected boolean storeDeoptTargetMethod() { return false; } @Override - protected boolean shouldInclude(ResolvedJavaMethod method, Infopoint infopoint) { + protected boolean includeLocalValues(ResolvedJavaMethod method, Infopoint infopoint) { CompilationInfo compilationInfo = ((HostedMethod) method).compilationInfo; BytecodeFrame topFrame = infopoint.debugInfo.frame(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java index 4997385e88af..4219c3b107fb 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java @@ -70,6 +70,7 @@ import com.oracle.svm.hosted.meta.HostedPrimitiveType; import com.oracle.svm.hosted.meta.HostedType; import com.oracle.svm.hosted.substitute.InjectedFieldsType; +import com.oracle.svm.hosted.substitute.SubstitutionField; import com.oracle.svm.hosted.substitute.SubstitutionMethod; import com.oracle.svm.hosted.substitute.SubstitutionType; @@ -84,7 +85,7 @@ * Implementation of the DebugInfoProvider API interface that allows type, code and heap data info * to be passed to an ObjectFile when generation of debug info is enabled. */ -class NativeImageDebugInfoProvider implements DebugInfoProvider { +public class NativeImageDebugInfoProvider implements DebugInfoProvider { private final DebugContext debugContext; private final NativeImageCodeCache codeCache; @SuppressWarnings("unused") private final NativeImageHeap heap; @@ -194,7 +195,7 @@ protected static ResolvedJavaType getDeclaringClass(HostedType hostedType, boole return hostedType.getWrapped().getWrapped(); } - protected static ResolvedJavaType getDeclaringClass(HostedMethod hostedMethod, boolean wantOriginal) { + public static ResolvedJavaType getDeclaringClass(HostedMethod hostedMethod, boolean wantOriginal) { if (wantOriginal) { return getOriginal(hostedMethod.getDeclaringClass()); } @@ -229,7 +230,17 @@ private static ResolvedJavaType getOriginal(HostedType hostedType) { return javaType; } - private static String toJavaName(JavaType javaType) { + private static int getOriginalModifiers(HostedMethod hostedMethod) { + ResolvedJavaMethod targetMethod = hostedMethod.getWrapped().getWrapped(); + if (targetMethod instanceof SubstitutionMethod) { + targetMethod = ((SubstitutionMethod) targetMethod).getOriginal(); + } else if (targetMethod instanceof CustomSubstitutionMethod) { + targetMethod = ((CustomSubstitutionMethod) targetMethod).getOriginal(); + } + return targetMethod.getModifiers(); + } + + public static String toJavaName(JavaType javaType) { if (javaType instanceof HostedType) { return getDeclaringClass((HostedType) javaType, true).toJavaName(); } @@ -608,7 +619,11 @@ public int size() { @Override public int modifiers() { - return field.getModifiers(); + ResolvedJavaField targetField = field.wrapped.wrapped; + if (targetField instanceof SubstitutionField) { + targetField = ((SubstitutionField) targetField).getOriginal(); + } + return targetField.getModifiers(); } private boolean isStatic() { @@ -683,7 +698,7 @@ public boolean isDeoptTarget() { @Override public int modifiers() { - return hostedMethod.getModifiers(); + return getOriginalModifiers(hostedMethod); } } } @@ -963,7 +978,7 @@ public List paramNames() { @Override public int modifiers() { - return hostedMethod.getModifiers(); + return getOriginalModifiers(hostedMethod); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java index 22afc4b3ebf1..ef5e14f0e7bc 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java @@ -418,6 +418,7 @@ private void addObjectToImageHeap(final Object object, boolean immutableFromPare written = true; } + assert hybridArray != null : "Cannot read value for field " + hybridArrayField.format("%H.%n"); size = hybridLayout.getTotalSize(Array.getLength(hybridArray)); } else { size = LayoutEncoding.getInstanceSize(hub.getLayoutEncoding()).rawValue(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java index 71c4684c9081..a06325b43b60 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java @@ -55,13 +55,11 @@ import com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo; import com.oracle.svm.hosted.meta.HostedClass; import com.oracle.svm.hosted.meta.HostedField; -import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.meta.MaterializedConstantFields; import com.oracle.svm.hosted.meta.MethodPointer; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaMethod; import sun.misc.Unsafe; /** @@ -242,14 +240,8 @@ private void addNonDataRelocation(RelocatableBuffer buffer, int index, Relocated mustBeReferenceAligned(index); assert pointer instanceof CFunctionPointer : "unknown relocated pointer " + pointer; assert pointer instanceof MethodPointer : "cannot create relocation for unknown FunctionPointer " + pointer; - - ResolvedJavaMethod method = ((MethodPointer) pointer).getMethod(); - HostedMethod hMethod = method instanceof HostedMethod ? (HostedMethod) method : heap.getUniverse().lookup(method); - if (hMethod.isCompiled()) { - // Only compiled methods inserted in vtables require relocation. - int pointerSize = ConfigurationValues.getTarget().wordSize; - addDirectRelocationWithoutAddend(buffer, index, pointerSize, pointer); - } + int pointerSize = ConfigurationValues.getTarget().wordSize; + addDirectRelocationWithoutAddend(buffer, index, pointerSize, pointer); } private static void writePrimitive(RelocatableBuffer buffer, int index, JavaConstant con) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/RelocatableBuffer.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/RelocatableBuffer.java index 0412c1c788eb..e6d473f46192 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/RelocatableBuffer.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/RelocatableBuffer.java @@ -53,11 +53,11 @@ public RelocatableBuffer(long size, ByteOrder byteOrder) { } public void addRelocationWithoutAddend(int key, ObjectFile.RelocationKind relocationKind, Object targetObject) { - relocations.put(key, new Info(relocationKind, null, targetObject)); + relocations.put(key, new Info(relocationKind, 0L, targetObject)); } - public void addRelocationWithAddend(int key, ObjectFile.RelocationKind relocationKind, Long explicitAddend, Object targetObject) { - relocations.put(key, new Info(relocationKind, explicitAddend, targetObject)); + public void addRelocationWithAddend(int key, ObjectFile.RelocationKind relocationKind, long addend, Object targetObject) { + relocations.put(key, new Info(relocationKind, addend, targetObject)); } public boolean hasRelocations() { @@ -78,7 +78,7 @@ public ByteBuffer getByteBuffer() { static final class Info { private final ObjectFile.RelocationKind relocationKind; - private final Long explicitAddend; + private final long addend; /** * The referenced object on the heap. If this is an instance of a {@link RelocatedPointer}, * than the relocation is not treated as a data relocation but has a special meaning, e.g. a @@ -86,9 +86,9 @@ static final class Info { */ private final Object targetObject; - Info(ObjectFile.RelocationKind kind, Long explicitAddend, Object targetObject) { + Info(ObjectFile.RelocationKind kind, long addend, Object targetObject) { this.relocationKind = kind; - this.explicitAddend = explicitAddend; + this.addend = addend; this.targetObject = targetObject; } @@ -100,12 +100,8 @@ public ObjectFile.RelocationKind getRelocationKind() { return relocationKind; } - public boolean hasExplicitAddend() { - return (explicitAddend != null); - } - - public Long getExplicitAddend() { - return explicitAddend; + public long getAddend() { + return addend; } public Object getTargetObject() { @@ -114,7 +110,7 @@ public Object getTargetObject() { @Override public String toString() { - return "RelocatableBuffer.Info(targetObject=" + targetObject + " relocationKind=" + relocationKind + " explicitAddend=" + explicitAddend + ")"; + return "RelocatableBuffer.Info(targetObject=" + targetObject + " relocationKind=" + relocationKind + " addend=" + addend + ")"; } } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java index 8fcbce1b5ca8..db79cf0e7819 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -40,16 +40,16 @@ import java.util.HashMap; import java.util.List; -import com.oracle.svm.core.util.VMError; -import com.oracle.svm.util.ModuleSupport; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.nativeimage.hosted.Feature; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.core.option.OptionUtils; +import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.ImageClassLoader; +import com.oracle.svm.util.ModuleSupport; /** * An abstract cache manager for some subspace of the JDK, GraalVM or application source file space. @@ -107,7 +107,7 @@ private void addJDKSources() { assert javaHome != null; Path javaHomePath = Paths.get("", javaHome); Path srcZipPath; - if (JavaVersionUtil.JAVA_SPEC < 11) { + if (JavaVersionUtil.JAVA_SPEC <= 8) { Path srcZipDir = javaHomePath.getParent(); if (srcZipDir == null) { VMError.shouldNotReachHere("Cannot resolve parent directory of " + javaHome); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKRegistrations.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKRegistrations.java index 0cb6f66e0d64..c1dc373bf787 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKRegistrations.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKRegistrations.java @@ -48,19 +48,19 @@ public void duringSetup(DuringSetupAccess a) { rerunClassInit(a, "java.lang.ProcessImpl", "java.lang.ProcessHandleImpl", "java.lang.ProcessHandleImpl$Info", "java.io.FilePermission"); } - if (JavaVersionUtil.JAVA_SPEC >= 15) { + if (JavaVersionUtil.JAVA_SPEC >= 17) { /* * Holds system and user library paths derived from the `java.library.path` and * `sun.boot.library.path` system properties. */ rerunClassInit(a, "jdk.internal.loader.NativeLibraries$LibraryPaths"); - } - if (JavaVersionUtil.JAVA_SPEC >= 16) { /* * Contains lots of state that is only available at run time: loads a native library, * stores a `Random` object and the temporary directory in a static final field. */ rerunClassInit(a, "sun.nio.ch.UnixDomainSockets"); + + rerunClassInit(a, "java.util.concurrent.ThreadLocalRandom$ThreadLocalRandomProxy"); } /* diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationAWTSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationAWTSupport.java index 1fbae0accd3e..dcf75b097238 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationAWTSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationAWTSupport.java @@ -25,6 +25,10 @@ package com.oracle.svm.hosted.jdk; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; + +import java.util.Optional; + +import org.graalvm.compiler.serviceprovider.GraalServices; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.hosted.Feature; @@ -32,9 +36,15 @@ import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.hosted.FeatureImpl.BeforeImageWriteAccessImpl; +import jdk.vm.ci.services.Services; + @Platforms(Platform.WINDOWS.class) @AutomaticFeature public class JNIRegistrationAWTSupport implements Feature { + + private static final int JDK_UPDATE = GraalServices.getJavaUpdateVersion(); + private static final boolean IS_OPENJDK = Optional.ofNullable(Services.getSavedProperties().get("java.vm.name")).orElse("").startsWith("OpenJDK"); + @Override public void beforeImageWrite(BeforeImageWriteAccess access) { JNIRegistrationSupport jniRegistrationSupport = JNIRegistrationSupport.singleton(); @@ -79,7 +89,12 @@ public void beforeImageWrite(BeforeImageWriteAccess access) { jniRegistrationSupport.addJavaShimExports( "JNU_ThrowClassNotFoundException"); } - if (jniRegistrationSupport.isRegisteredLibrary("fontmanager") && JavaVersionUtil.JAVA_SPEC >= 11) { + // harfbuzz became a separate library in OpenJDK 16/11.0.10 (JDK-8249821) and then went back + // to be included in fontmanager library in OpenJDK 17/11.0.13 (or 11.0.12 for OracleJDK). + // See JDK-8255790. + int jdk11HbUpdateBound = IS_OPENJDK ? 12 : 11; + if (jniRegistrationSupport.isRegisteredLibrary("fontmanager") && + ((JavaVersionUtil.JAVA_SPEC == 11 && JDK_UPDATE >= 10 && JDK_UPDATE <= jdk11HbUpdateBound) || JavaVersionUtil.JAVA_SPEC == 16)) { /* * Dependency on `harfbuzz` may not be expressed in Java, so we register it manually * here just in case. diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationAwt.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationAwt.java index d3f4f829fb93..3586b1225d3a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationAwt.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationAwt.java @@ -33,7 +33,11 @@ import com.oracle.svm.core.jni.JNIRuntimeAccess; import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.c.NativeLibraries; + +import jdk.vm.ci.services.Services; + import org.graalvm.compiler.serviceprovider.JavaVersionUtil; +import org.graalvm.compiler.serviceprovider.GraalServices; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -42,12 +46,16 @@ import org.graalvm.nativeimage.impl.InternalPlatform; import java.awt.GraphicsEnvironment; +import java.util.Optional; @Platforms({InternalPlatform.PLATFORM_JNI.class}) @AutomaticFeature @SuppressWarnings({"unused"}) public class JNIRegistrationAwt extends JNIRegistrationUtil implements Feature { + private static final int JDK_UPDATE = GraalServices.getJavaUpdateVersion(); + private static final boolean IS_OPENJDK = Optional.ofNullable(Services.getSavedProperties().get("java.vm.name")).orElse("").startsWith("OpenJDK"); + @Override public void beforeAnalysis(BeforeAnalysisAccess access) { if (JavaVersionUtil.JAVA_SPEC >= 11 && Platform.includedIn(Platform.LINUX.class)) { @@ -161,7 +169,13 @@ private static void registerFreeType(DuringAnalysisAccess access) { NativeLibrarySupport.singleton().preregisterUninitializedBuiltinLibrary("fontmanager"); nativeLibraries.addStaticJniLibrary("fontmanager", isHeadless() ? "awt_headless" : "awt_xawt"); - nativeLibraries.addStaticJniLibrary("harfbuzz"); + // harfbuzz became a separate library in OpenJDK 16/11.0.10 (JDK-8249821) and then went back + // to be included in fontmanager library in OpenJDK 17/11.0.13 (or 11.0.12 for OracleJDK). + // See JDK-8255790. + int jdk11HbUpdateBound = IS_OPENJDK ? 12 : 11; + if (JavaVersionUtil.JAVA_SPEC == 16 || (JavaVersionUtil.JAVA_SPEC == 11 && JDK_UPDATE >= 10 && JDK_UPDATE <= jdk11HbUpdateBound)) { + nativeLibraries.addStaticJniLibrary("harfbuzz"); + } nativeLibraries.addDynamicNonJniLibrary("freetype"); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java index c0e2ba381a3e..d8252d5cbad5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNet.java @@ -61,10 +61,12 @@ public void duringSetup(DuringSetupAccess a) { rerunClassInit(a, "java.net.DatagramPacket", "java.net.InetAddress", "java.net.NetworkInterface", "java.net.SocketInputStream", "java.net.SocketOutputStream", /* Caches networking properties. */ - "java.net.DefaultDatagramSocketImplFactory"); + "java.net.DefaultDatagramSocketImplFactory", + /* Stores a default SSLContext in a static field. */ + "javax.net.ssl.SSLContext"); if (isWindows()) { rerunClassInit(a, "java.net.DualStackPlainDatagramSocketImpl", "java.net.TwoStacksPlainDatagramSocketImpl"); - if (JavaVersionUtil.JAVA_SPEC < 11) { + if (JavaVersionUtil.JAVA_SPEC <= 8) { rerunClassInit(a, "java.net.DualStackPlainSocketImpl", "java.net.TwoStacksPlainSocketImpl", /* Caches networking properties. */ "java.net.PlainSocketImpl"); @@ -134,7 +136,7 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { a.registerReachabilityHandler(JNIRegistrationJavaNet::registerDatagramPacketInit, method(a, "java.net.DatagramPacket", "init")); - if (JavaVersionUtil.JAVA_SPEC < 15) { + if (JavaVersionUtil.JAVA_SPEC <= 11) { a.registerReachabilityHandler(JNIRegistrationJavaNet::registerDatagramSocketCheckOldImpl, method(a, "java.net.DatagramSocket", "checkOldImpl")); } @@ -145,7 +147,7 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainDatagramSocketImplSocketGetOption, method(a, "java.net." + plainDatagramSocketImpl, "socketGetOption", int.class)); - if (JavaVersionUtil.JAVA_SPEC < 11 || isPosix()) { + if (JavaVersionUtil.JAVA_SPEC <= 8 || isPosix()) { String plainSocketImpl = isWindows() ? "TwoStacksPlainSocketImpl" : "PlainSocketImpl"; a.registerReachabilityHandler(JNIRegistrationJavaNet::registerPlainSocketImplInitProto, method(a, "java.net." + plainSocketImpl, "initProto")); @@ -156,7 +158,7 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { a.registerReachabilityHandler(JNIRegistrationJavaNet::registerDualStackPlainDatagramSocketImplInitIDs, method(a, "java.net.DualStackPlainDatagramSocketImpl", "initIDs")); - String dualStackPlainSocketImpl = JavaVersionUtil.JAVA_SPEC < 11 ? "DualStackPlainSocketImpl" : "PlainSocketImpl"; + String dualStackPlainSocketImpl = JavaVersionUtil.JAVA_SPEC <= 8 ? "DualStackPlainSocketImpl" : "PlainSocketImpl"; a.registerReachabilityHandler(JNIRegistrationJavaNet::registerDualStackPlainSocketImplInitIDs, method(a, "java.net." + dualStackPlainSocketImpl, "initIDs")); a.registerReachabilityHandler(JNIRegistrationJavaNet::registerDualStackPlainSocketImplLocalAddress, @@ -192,7 +194,7 @@ static void registerInitInetAddressIDs(DuringAnalysisAccess a) { /* Java_java_net_Inet6Address_init */ JNIRuntimeAccess.register(constructor(a, "java.net.Inet6Address")); JNIRuntimeAccess.register(fields(a, "java.net.Inet6Address", "holder6")); - if (JavaVersionUtil.JAVA_SPEC < 13) { // JDK-8216417 + if (JavaVersionUtil.JAVA_SPEC <= 11) { // JDK-8216417 Class c = clazz(a, "java.net.Inet6Address"); boolean optional = JavaVersionUtil.JAVA_SPEC == 11; // JDK-8269385 Field f = ReflectionUtil.lookupField(optional, c, "cached_scope_id"); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNio.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNio.java index cde3bd53cf0f..3de0a1775c45 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNio.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationJavaNio.java @@ -86,9 +86,6 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { if (isPosix()) { a.registerReachabilityHandler(registerServerSocketChannelImplInitIDs, method(a, "sun.nio.ch.UnixAsynchronousServerSocketChannelImpl", "initIDs")); } - } - - if (JavaVersionUtil.JAVA_SPEC < 13) { a.registerReachabilityHandler(JNIRegistrationJavaNio::registerDatagramChannelImplInitIDs, method(a, "sun.nio.ch.DatagramChannelImpl", "initIDs")); } else { // JDK-8220738 @@ -111,15 +108,17 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { a.registerReachabilityHandler(JNIRegistrationJavaNio::registerConnectionCreateInetSocketAddress, method(a, "com.sun.jndi.ldap.Connection", "createInetSocketAddress", String.class, int.class)); Consumer registerInitInetAddressIDs = JNIRegistrationJavaNet::registerInitInetAddressIDs; - if (JavaVersionUtil.JAVA_SPEC < 9) { + if (JavaVersionUtil.JAVA_SPEC <= 8) { a.registerReachabilityHandler(registerInitInetAddressIDs, method(a, "sun.nio.ch.IOUtil", "initIDs")); } else { a.registerReachabilityHandler(registerInitInetAddressIDs, method(a, "sun.nio.ch.Net", "initIDs")); } - // In JDK 14, all of the Buffer classes require MemorySegmentProxy which is accessed via - // reflection - if (JavaVersionUtil.JAVA_SPEC >= 14) { + /* + * Starting with support for JDK 17, all of the Buffer classes require MemorySegmentProxy + * which is accessed via reflection. + */ + if (JavaVersionUtil.JAVA_SPEC >= 17) { RuntimeReflection.register(clazz(a, "jdk.internal.access.foreign.MemorySegmentProxy")); } } @@ -200,7 +199,7 @@ private static void registerWindowsNativeDispatcherInitIDs(DuringAnalysisAccess JNIRuntimeAccess.register(fields(a, "sun.nio.fs.WindowsNativeDispatcher$VolumeInformation", "fileSystemName", "volumeName", "volumeSerialNumber", "flags")); JNIRuntimeAccess.register(clazz(a, "sun.nio.fs.WindowsNativeDispatcher$DiskFreeSpace")); JNIRuntimeAccess.register(fields(a, "sun.nio.fs.WindowsNativeDispatcher$DiskFreeSpace", "freeBytesAvailable", "totalNumberOfBytes", "totalNumberOfFreeBytes")); - if (JavaVersionUtil.JAVA_SPEC >= 10) { + if (JavaVersionUtil.JAVA_SPEC >= 11) { JNIRuntimeAccess.register(fields(a, "sun.nio.fs.WindowsNativeDispatcher$DiskFreeSpace", "bytesPerSector")); } JNIRuntimeAccess.register(clazz(a, "sun.nio.fs.WindowsNativeDispatcher$Account")); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationSupport.java index 69f744d2f4bc..3a464b68ef45 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationSupport.java @@ -76,7 +76,7 @@ /** Registration of native JDK libraries. */ @Platforms(InternalPlatform.PLATFORM_JNI.class) @AutomaticFeature -class JNIRegistrationSupport extends JNIRegistrationUtil implements GraalFeature { +public final class JNIRegistrationSupport extends JNIRegistrationUtil implements GraalFeature { private final ConcurrentMap registeredLibraries = new ConcurrentHashMap<>(); private NativeLibraries nativeLibraries = null; @@ -103,7 +103,7 @@ public void registerGraphBuilderPlugins(Providers providers, Plugins plugins, Pa registerLoadLibraryPlugin(plugins, System.class); } - void registerLoadLibraryPlugin(Plugins plugins, Class clazz) { + public void registerLoadLibraryPlugin(Plugins plugins, Class clazz) { Registration r = new Registration(plugins.getInvocationPlugins(), clazz); r.register1("loadLibrary", String.class, new InvocationPlugin() { @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/CharsetSubstitutionsFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/CharsetSubstitutionsFeature.java similarity index 97% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/CharsetSubstitutionsFeature.java rename to substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/CharsetSubstitutionsFeature.java index 686e9aa10f63..15d2773d6202 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/CharsetSubstitutionsFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/CharsetSubstitutionsFeature.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk.localization; +package com.oracle.svm.hosted.jdk.localization; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.hosted.Feature; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/LocalizationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/LocalizationFeature.java new file mode 100644 index 000000000000..f9ae1e9369e6 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/LocalizationFeature.java @@ -0,0 +1,594 @@ +/* + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.jdk.localization; + +// Checkstyle: stop + +import java.lang.reflect.Field; +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.StandardCharsets; +import java.nio.charset.UnsupportedCharsetException; +import java.text.spi.BreakIteratorProvider; +import java.text.spi.CollatorProvider; +import java.text.spi.DateFormatProvider; +import java.text.spi.DateFormatSymbolsProvider; +import java.text.spi.DecimalFormatSymbolsProvider; +import java.text.spi.NumberFormatProvider; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.IllformedLocaleException; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.Objects; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.concurrent.ForkJoinPool; +import java.util.function.Function; +import java.util.spi.CalendarDataProvider; +import java.util.spi.CalendarNameProvider; +import java.util.spi.CurrencyNameProvider; +import java.util.spi.LocaleNameProvider; +import java.util.spi.LocaleServiceProvider; +import java.util.spi.TimeZoneNameProvider; + +import com.oracle.svm.core.jdk.localization.BundleContentSubstitutedLocalizationSupport; +import com.oracle.svm.core.jdk.localization.LocalizationSupport; +import com.oracle.svm.core.jdk.localization.OptimizedLocalizationSupport; +import com.oracle.svm.hosted.NativeImageOptions; +import com.oracle.svm.core.jdk.localization.compression.GzipBundleCompression; +import com.oracle.svm.core.jdk.localization.substitutions.Target_sun_util_locale_provider_LocaleServiceProviderPool_OptimizedLocaleMode; +import org.graalvm.collections.Pair; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.serviceprovider.JavaVersionUtil; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.hosted.Feature; + +import com.oracle.svm.core.ClassLoaderSupport; +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.option.HostedOptionKey; +import com.oracle.svm.core.option.LocatableMultiOptionValue; +import com.oracle.svm.core.option.OptionUtils; +import com.oracle.svm.core.util.UserError; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.util.ReflectionUtil; + +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.ResourceBundleBasedAdapter; +import sun.util.resources.LocaleData; +// Checkstyle: resume + +/** + * LocalizationFeature is the core class of SVM localization support. It contains all the options + * that can be used to configure how localization in the resulting image should work. One can + * specify what charsets, locales and resource bundles should be accessible. The runtime data for + * localization is stored in an image singleton of type {@link LocalizationSupport} or one of its + * subtypes. + * + * In case of ResourceBundles, one can also specify how bundles should be handled, because currently + * there are two different modes. + * + * The first approach is using a simple in memory map instead of the original JDK lookup. This + * simpler implementation leads to image size savings for smaller images such as hello world, but + * could cause compatibility issues and maintenance overhead. It is implemented in + * {@link OptimizedLocalizationSupport}. + * + * The second approach relies on the original JVM implementation instead. This approach is + * consistent by design, which solves compatibility issues and reduces maintenance overhead. + * Unfortunately, the default way of storing bundle data in getContents methods, see + * {@link sun.text.resources.FormatData} for example, is not very AOT friendly. Compiling these + * methods is time consuming and results in a bloated image (183 MB HelloWorld with all locales). + * Therefore, the bundle content itself is again stored in the image heap by default and furthermore + * is compressed to reduce the image size, see {@link BundleContentSubstitutedLocalizationSupport} + * and {@link GzipBundleCompression}. + * + * @author d-kozak + * @see LocalizationSupport + * @see OptimizedLocalizationSupport + * @see BundleContentSubstitutedLocalizationSupport + */ +public abstract class LocalizationFeature implements Feature { + + protected final boolean optimizedMode = Options.LocalizationOptimizedMode.getValue(); + + private final boolean substituteLoadLookup = Options.LocalizationSubstituteLoadLookup.getValue(); + + protected final boolean trace = Options.TraceLocalizationFeature.getValue(); + + private final ForkJoinPool compressionPool = Options.LocalizationCompressInParallel.getValue() ? new ForkJoinPool(NativeImageOptions.NumberOfThreads.getValue()) : null; + + /** + * The Locale that the native image is built for. Currently, switching the Locale at run time is + * not supported because the resource bundles are only included for one Locale. We use the + * Locale that is set for the image generator. + */ + protected Locale defaultLocale = Locale.getDefault(); + + private Charset defaultCharset; + + protected Set allLocales; + + protected LocalizationSupport support; + + private Function> findClassByName; + + public static class Options { + @Option(help = "Comma separated list of bundles to be included into the image.", type = OptionType.User)// + public static final HostedOptionKey IncludeResourceBundles = new HostedOptionKey<>(new LocatableMultiOptionValue.Strings()); + + @Option(help = "Make all hosted charsets available at run time")// + public static final HostedOptionKey AddAllCharsets = new HostedOptionKey<>(false); + + @Option(help = "Default locale of the image, by the default it is the same as the default locale of the image builder.", type = OptionType.User)// + public static final HostedOptionKey DefaultLocale = new HostedOptionKey<>(Locale.getDefault().toLanguageTag()); + + @Option(help = "Default charset of the image, by the default it is the same as the default charset of the image builder.", type = OptionType.User)// + public static final HostedOptionKey DefaultCharset = new HostedOptionKey<>(Charset.defaultCharset().name()); + + @Option(help = "Comma separated list of locales to be included into the image. The default locale is included in the list automatically if not present.", type = OptionType.User)// + public static final HostedOptionKey IncludeLocales = new HostedOptionKey<>(new LocatableMultiOptionValue.Strings()); + + @Option(help = "Make all hosted locales available at run time.", type = OptionType.User)// + public static final HostedOptionKey IncludeAllLocales = new HostedOptionKey<>(false); + + @Option(help = "Optimize the resource bundle lookup using a simple map.", type = OptionType.User)// + public static final HostedOptionKey LocalizationOptimizedMode = new HostedOptionKey<>(JavaVersionUtil.JAVA_SPEC == 8); + + @Option(help = "Store the resource bundle content more efficiently in the fallback mode.", type = OptionType.User)// + public static final HostedOptionKey LocalizationSubstituteLoadLookup = new HostedOptionKey<>(true); + + @Option(help = "Regular expressions matching which bundles should be compressed.", type = OptionType.User)// + public static final HostedOptionKey LocalizationCompressBundles = new HostedOptionKey<>(new LocatableMultiOptionValue.Strings()); + + @Option(help = "Compress the bundles in parallel.", type = OptionType.Expert)// + public static final HostedOptionKey LocalizationCompressInParallel = new HostedOptionKey<>(true); + + @Option(help = "When enabled, localization feature details are printed.", type = OptionType.Debug)// + public static final HostedOptionKey TraceLocalizationFeature = new HostedOptionKey<>(false); + } + + /** + * Many subclasses of {@link Charset} initialize encoding and decoding tables lazily. They all + * follow the same pattern: the methods "initc2b" and/or "initb2c" perform the initialization, + * and then set a field "c2bInitialized" or "b2cInitialized" to true. We run the initialization + * eagerly by creating an encoder and decoder during image generation in + * {@link LocalizationFeature#addCharset}. So we know that the "init*" methods do nothing, and + * we replace calls to them with nothing, i.e,, remove calls to them. + * + * We could do all this with individual {@link Substitute method substitutions}, but it would + * require a lot of substitution methods that all look the same. + */ + public static final class CharsetNodePlugin implements NodePlugin { + + @Override + public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + if ((method.getName().equals("initc2b") || method.getName().equals("initb2c")) && + b.getMetaAccess().lookupJavaType(Charset.class).isAssignableFrom(method.getDeclaringClass())) { + + /* + * Verify that the "*Initialized" field corresponding with the method was set to + * true, i.e., that initialization was done eagerly. + */ + ResolvedJavaType charsetType = method.getDeclaringClass(); + ResolvedJavaField initializedField = findStaticField(charsetType, method.getName().substring(4, 7) + "Initialized"); + if (!b.getConstantReflection().readFieldValue(initializedField, null).asBoolean()) { + String charsetName = charsetType.getUnqualifiedName(); + try { + Charset charset = Charset.forName(charsetName); + addCharset(charset); + } catch (UnsupportedCharsetException e) { + throw VMError.shouldNotReachHere("Could not find non-initialized charset " + charsetType.getSourceFileName(), e); + } + } + + /* We "handled" the method invocation by doing nothing. */ + return true; + } + return false; + } + + private static ResolvedJavaField findStaticField(ResolvedJavaType declaringClass, String name) { + for (ResolvedJavaField field : declaringClass.getStaticFields()) { + if (field.getName().equals(name)) { + return field; + } + } + throw VMError.shouldNotReachHere(); + } + } + + @Override + public void afterRegistration(AfterRegistrationAccess access) { + findClassByName = access::findClassByName; + allLocales = processLocalesOption(); + defaultLocale = parseLocaleFromTag(Options.DefaultLocale.getValue()); + UserError.guarantee(defaultLocale != null, "Invalid default locale %s", Options.DefaultLocale.getValue()); + try { + defaultCharset = Charset.forName(Options.DefaultCharset.getValue()); + VMError.guarantee(defaultCharset.name().equals(Options.DefaultCharset.getValue()), + "Failed to locate charset " + Options.DefaultCharset.getValue() + ", instead " + defaultCharset.name() + " was provided"); + } catch (IllegalCharsetNameException | UnsupportedCharsetException ex) { + throw UserError.abort(ex, "Invalid default charset %s", Options.DefaultCharset.getValue()); + } + allLocales.add(defaultLocale); + support = selectLocalizationSupport(); + ImageSingletons.add(LocalizationSupport.class, support); + ImageSingletons.add(LocalizationFeature.class, this); + + addCharsets(); + if (optimizedMode) { + /* + * Providers are only preprocessed in the optimized mode. + */ + addProviders(); + } + } + + @Override + public void duringSetup(DuringSetupAccess access) { + if (optimizedMode) { + access.registerObjectReplacer(this::eagerlyInitializeBundles); + } + } + + /** + * In the optimized localization support, the bundles are stored in a map. In order to make the + * getContents methods unreachable, the bundles are initialized eagerly and the lookup methods + * are substituted. However, if there are bundle instances somewhere in the heap that were not + * put in the map, they won't be initialized and therefore accessing their content will cause + * runtime failures. Therefore, we visit each object in the heap and if it is a ResourceBundle, + * we eagerly initialize it. + */ + private Object eagerlyInitializeBundles(Object object) { + assert optimizedMode : "Should only be triggered in the optimized mode."; + if (object instanceof ResourceBundle) { + ResourceBundle bundle = (ResourceBundle) object; + try { + /* + * getKeys can be null for ResourceBundle.NONEXISTENT_BUNDLE, which causes the + * keySet method to crash. + */ + if (bundle.getKeys() != null) { + bundle.keySet(); + } + } catch (Exception ex) { + trace("Failed to eagerly initialize bundle " + bundle + ", " + bundle.getBaseBundleName() + ", reason " + ex.getClass() + " " + ex.getMessage()); + } + } + return object; + } + + @Platforms(Platform.HOSTED_ONLY.class) + private LocalizationSupport selectLocalizationSupport() { + if (optimizedMode) { + return new OptimizedLocalizationSupport(defaultLocale, allLocales, defaultCharset); + } else if (substituteLoadLookup) { + List requestedPatterns = Options.LocalizationCompressBundles.getValue().values(); + return new BundleContentSubstitutedLocalizationSupport(defaultLocale, allLocales, defaultCharset, requestedPatterns, compressionPool); + } + return new LocalizationSupport(defaultLocale, allLocales, defaultCharset); + } + + @Override + public void beforeAnalysis(BeforeAnalysisAccess access) { + addResourceBundles(); + } + + @Override + public void afterAnalysis(AfterAnalysisAccess access) { + if (compressionPool != null) { + compressionPool.shutdown(); + } + } + + /** + * @return locale for given tag or null for invalid ones + */ + @Platforms(Platform.HOSTED_ONLY.class) + private static Locale parseLocaleFromTag(String tag) { + try { + return new Locale.Builder().setLanguageTag(tag).build(); + } catch (IllformedLocaleException ex) { + /*- Custom made locales consisting of at most three parts separated by '-' are also supported */ + String[] parts = tag.split("-"); + switch (parts.length) { + case 1: + return new Locale(parts[0]); + case 2: + return new Locale(parts[0], parts[1]); + case 3: + return new Locale(parts[0], parts[1], parts[2]); + default: + return null; + } + } + } + + @Platforms(Platform.HOSTED_ONLY.class) + private static Set processLocalesOption() { + Set locales = new HashSet<>(); + if (Options.IncludeAllLocales.getValue()) { + Collections.addAll(locales, Locale.getAvailableLocales()); + /*- Fallthrough to also allow adding custom locales */ + } + List invalid = new ArrayList<>(); + for (String tag : OptionUtils.flatten(",", Options.IncludeLocales.getValue().values())) { + Locale locale = parseLocaleFromTag(tag); + if (locale != null) { + locales.add(locale); + } else { + invalid.add(tag); + } + } + if (!invalid.isEmpty()) { + throw UserError.abort("Invalid locales specified: %s", invalid); + } + return locales; + } + + /** + * The JDK performs dynamic lookup of charsets by name, which leads to dynamic class loading. We + * cannot do that, because we need to know all classes ahead of time to perform our static + * analysis. Therefore, we load and register all standard charsets here. Features that require + * more than this can add additional charsets. + */ + @Platforms(Platform.HOSTED_ONLY.class) + private void addCharsets() { + if (Options.AddAllCharsets.getValue()) { + for (Charset c : Charset.availableCharsets().values()) { + addCharset(c); + } + } else { + addCharset(defaultCharset); + addCharset(StandardCharsets.US_ASCII); + addCharset(StandardCharsets.ISO_8859_1); + addCharset(StandardCharsets.UTF_8); + addCharset(StandardCharsets.UTF_16BE); + addCharset(StandardCharsets.UTF_16LE); + addCharset(StandardCharsets.UTF_16); + } + } + + @Platforms(Platform.HOSTED_ONLY.class) + public static void addCharset(Charset charset) { + Map charsets = ImageSingletons.lookup(LocalizationSupport.class).charsets; + charsets.put(charset.name().toLowerCase(), charset); + for (String name : charset.aliases()) { + charsets.put(name.toLowerCase(), charset); + } + + /* Eagerly initialize all the tables necessary for decoding / encoding. */ + charset.newDecoder(); + if (charset.canEncode()) { + charset.newEncoder(); + } + } + + /* + * LocaleServiceProviderPool.spiClasses does not contain all the classes we need, so we list + * them manually here. + */ + private static final List> spiClasses = Arrays.asList( + BreakIteratorProvider.class, + CollatorProvider.class, + DateFormatProvider.class, + DateFormatSymbolsProvider.class, + DecimalFormatSymbolsProvider.class, + NumberFormatProvider.class, + CurrencyNameProvider.class, + LocaleNameProvider.class, + TimeZoneNameProvider.class, + CalendarDataProvider.class, + CalendarNameProvider.class); + + @Platforms(Platform.HOSTED_ONLY.class) + protected List> getSpiClasses() { + return spiClasses; + } + + @Platforms(Platform.HOSTED_ONLY.class) + private void addProviders() { + OptimizedLocalizationSupport optimizedLocalizationSupport = support.asOptimizedSupport(); + for (Class providerClass : getSpiClasses()) { + LocaleProviderAdapter adapter = Objects.requireNonNull(LocaleProviderAdapter.getAdapter(providerClass, defaultLocale)); + LocaleServiceProvider provider = Objects.requireNonNull(adapter.getLocaleServiceProvider(providerClass)); + optimizedLocalizationSupport.providerPools.put(providerClass, new Target_sun_util_locale_provider_LocaleServiceProviderPool_OptimizedLocaleMode(provider)); + } + + for (Locale locale : allLocales) { + for (Locale candidateLocale : optimizedLocalizationSupport.control.getCandidateLocales("", locale)) { + for (Class providerClass : getSpiClasses()) { + LocaleProviderAdapter adapter = Objects.requireNonNull(LocaleProviderAdapter.getAdapter(providerClass, candidateLocale)); + + optimizedLocalizationSupport.adaptersByClass.put(Pair.create(providerClass, candidateLocale), adapter); + LocaleProviderAdapter existing = optimizedLocalizationSupport.adaptersByType.put(adapter.getAdapterType(), adapter); + assert existing == null || existing == adapter : "Overwriting adapter type with a different adapter"; + + } + } + } + } + + @Platforms(Platform.HOSTED_ONLY.class) + protected void addResourceBundles() { + for (Locale locale : allLocales) { + prepareBundle(localeData(java.util.spi.CalendarDataProvider.class, locale).getCalendarData(locale), locale); + prepareBundle(localeData(java.util.spi.CurrencyNameProvider.class, locale).getCurrencyNames(locale), locale); + prepareBundle(localeData(java.util.spi.LocaleNameProvider.class, locale).getLocaleNames(locale), locale); + prepareBundle(localeData(java.util.spi.TimeZoneNameProvider.class, locale).getTimeZoneNames(locale), locale); + prepareBundle(localeData(java.text.spi.BreakIteratorProvider.class, locale).getBreakIteratorInfo(locale), locale); + prepareBundle(localeData(java.text.spi.BreakIteratorProvider.class, locale).getCollationData(locale), locale); + prepareBundle(localeData(java.text.spi.DateFormatProvider.class, locale).getDateFormatData(locale), locale); + prepareBundle(localeData(java.text.spi.NumberFormatProvider.class, locale).getNumberFormatData(locale), locale); + /* Note that JDK 11 support overrides this method to register more bundles. */ + } + + final String[] alwaysRegisteredResourceBundles = new String[]{ + "sun.util.logging.resources.logging", + "sun.util.resources.TimeZoneNames" + }; + for (String bundleName : alwaysRegisteredResourceBundles) { + prepareBundle(bundleName); + } + + for (String bundleName : OptionUtils.flatten(",", Options.IncludeResourceBundles.getValue())) { + processRequestedBundle(bundleName); + } + } + + @Platforms(Platform.HOSTED_ONLY.class) + protected LocaleData localeData(Class providerClass, Locale locale) { + return ((ResourceBundleBasedAdapter) LocaleProviderAdapter.getAdapter(providerClass, locale)).getLocaleData(); + } + + @Platforms(Platform.HOSTED_ONLY.class) + private void processRequestedBundle(String input) { + int splitIndex = input.indexOf('_'); + boolean specificLocaleRequested = splitIndex != -1; + if (!specificLocaleRequested) { + prepareBundle(input, allLocales); + return; + } + Locale locale = splitIndex + 1 < input.length() ? parseLocaleFromTag(input.substring(splitIndex + 1)) : Locale.ROOT; + if (locale == null) { + trace("Cannot parse wanted locale " + input.substring(splitIndex + 1) + ", default will be used instead."); + locale = defaultLocale; + } + /*- Get rid of locale specific suffix. */ + String baseName = input.substring(0, splitIndex); + prepareBundle(baseName, Collections.singletonList(locale)); + } + + @Platforms(Platform.HOSTED_ONLY.class) + public void prepareBundle(String baseName) { + prepareBundle(baseName, allLocales); + } + + @Platforms(Platform.HOSTED_ONLY.class) + public void prepareBundle(String baseName, Collection wantedLocales) { + if (baseName.isEmpty()) { + return; + } + + boolean somethingFound = false; + for (Locale locale : wantedLocales) { + List resourceBundle; + try { + resourceBundle = ImageSingletons.lookup(ClassLoaderSupport.class).getResourceBundle(baseName, locale); + } catch (MissingResourceException mre) { + continue; + } + somethingFound = !resourceBundle.isEmpty(); + for (ResourceBundle bundle : resourceBundle) { + prepareBundle(baseName, bundle, locale); + } + } + + if (!somethingFound) { + /* + * Try non-compliant class-based bundles. These bundles can't be looked up by the normal + * ResourceBundle lookup process, e.g. because they don't have default constructors. + */ + Class clazz = findClassByName.apply(baseName); + if (clazz != null && ResourceBundle.class.isAssignableFrom(clazz)) { + trace("Found non-compliant class-based bundle " + clazz); + somethingFound = true; + support.prepareNonCompliant(clazz); + } + } + + if (!somethingFound) { + String errorMessage = "The bundle named: " + baseName + ", has not been found. " + + "If the bundle is part of a module, verify the bundle name is a fully qualified class name. Otherwise " + + "verify the bundle path is accessible in the classpath."; + // Checkstyle: stop + System.out.println(errorMessage); + // Checkstyle: resume + } + } + + @Platforms(Platform.HOSTED_ONLY.class) + protected void prepareBundle(ResourceBundle bundle, Locale locale) { + prepareBundle(bundle.getBaseBundleName(), bundle, locale); + } + + @Platforms(Platform.HOSTED_ONLY.class) + private void prepareBundle(String bundleName, ResourceBundle bundle, Locale locale) { + trace("Adding bundle " + bundleName + ", locale " + locale); + /* + * Ensure that the bundle contents are loaded. We need to walk the whole bundle parent chain + * down to the root. + */ + for (ResourceBundle cur = bundle; cur != null; cur = getParent(cur)) { + /* Register all bundles with their corresponding locales */ + support.prepareBundle(bundleName, cur, cur.getLocale()); + } + + /* + * Finally, register the requested bundle with requested locale (Requested might be more + * specific than the actual bundle locale + */ + support.prepareBundle(bundleName, bundle, locale); + } + + /* + * The field ResourceBundle.parent is not public. There is a backdoor to access it via + * SharedSecrets, but the package of SharedSecrets changed from JDK 8 to JDK 11 so it is + * inconvenient to use it. Reflective access is easier. + */ + private static final Field PARENT_FIELD = ReflectionUtil.lookupField(ResourceBundle.class, "parent"); + + @Platforms(Platform.HOSTED_ONLY.class) + private static ResourceBundle getParent(ResourceBundle bundle) { + try { + return (ResourceBundle) PARENT_FIELD.get(bundle); + } catch (ReflectiveOperationException ex) { + throw VMError.shouldNotReachHere(ex); + } + } + + @Platforms(Platform.HOSTED_ONLY.class) + protected void trace(String msg) { + if (trace) { + // Checkstyle: stop + System.out.println(msg); + // Checkstyle: resume + } + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaProxyRenamingSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaProxyRenamingSubstitutionProcessor.java index 7afc2101255b..7f0fcb1f9566 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaProxyRenamingSubstitutionProcessor.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaProxyRenamingSubstitutionProcessor.java @@ -24,22 +24,23 @@ */ package com.oracle.svm.hosted.lambda; -import org.graalvm.compiler.java.LambdaUtils; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugContext.Builder; +import org.graalvm.compiler.java.LambdaUtils; import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.phases.util.Providers; import org.graalvm.compiler.printer.GraalDebugHandlersFactory; import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; -import com.oracle.svm.hosted.c.GraalAccess; -import com.oracle.svm.hosted.phases.NoClassInitializationPlugin; +import com.oracle.graal.pointsto.phases.NoClassInitializationPlugin; +import com.oracle.graal.pointsto.util.GraalAccess; + import jdk.vm.ci.meta.ResolvedJavaType; -import org.graalvm.compiler.phases.util.Providers; /** * This substitution replaces all lambda proxy types with types that have a stable names. The name diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstitutionType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstitutionType.java index 3e30f126d84c..84942e4bbbf6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstitutionType.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstitutionType.java @@ -27,8 +27,8 @@ import java.lang.annotation.Annotation; import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.jdk.LambdaFormHiddenMethod; -import com.oracle.svm.hosted.c.GraalAccess; import jdk.vm.ci.meta.Assumptions.AssumptionResult; import jdk.vm.ci.meta.JavaConstant; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java index 6b9e2e9d8ae0..e0d9f51c1cb7 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java @@ -151,6 +151,7 @@ public JavaConstant readValue(JavaConstant receiver) { public JavaConstant readStorageValue(JavaConstant receiver) { JavaConstant result = readValue(receiver); + assert result != null : "Cannot read value for field " + this.format("%H.%n"); assert result.getJavaKind() == getType().getStorageKind() : this; return result; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java index 260c4ff004ca..13d035dabe57 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java @@ -488,7 +488,11 @@ public int compareTo(HostedMethod other) { if (result == 0) { result = ((HostedType) this.getSignature().getReturnType(null)).compareTo((HostedType) other.getSignature().getReturnType(null)); } - assert result != 0; + /* + * Note that the result can still be 0 at this point: with class substitutions or incomplete + * classpath, two separate methods can have the same signature. Not ordering such methods is + * fine. GR-32976 should remove the sorting altogether. + */ return result; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java index 13c3f3f4b0c0..2551b7cba9b4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java @@ -163,7 +163,8 @@ public HostedMethod lookup(JavaMethod method) { if (result instanceof ResolvedJavaMethod) { return (HostedMethod) result; } - throw new UnsupportedFeatureException("Unresolved method found. Probably there are some compilation or classpath problems. " + method.format("%H.%n(%p)")); + throw new UnsupportedFeatureException("Unresolved method found: " + (method != null ? method.format("%H.%n(%p)") : "null") + + ". Probably there are some compilation or classpath problems. "); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/MethodPointer.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/MethodPointer.java index d6c92fbcf01e..d2af190eba9b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/MethodPointer.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/MethodPointer.java @@ -26,6 +26,8 @@ import static com.oracle.svm.core.util.VMError.shouldNotReachHere; +import java.util.Objects; + import org.graalvm.nativeimage.c.function.CFunctionPointer; import org.graalvm.word.ComparableWord; @@ -34,20 +36,11 @@ /** * A pointer to the compiled code of a method. */ -public class MethodPointer implements CFunctionPointer { - +public final class MethodPointer implements CFunctionPointer { private final ResolvedJavaMethod method; - public static CFunctionPointer factory(ResolvedJavaMethod method) { - if (method == null) { - return null; - } else { - return new MethodPointer(method); - } - } - - protected MethodPointer(ResolvedJavaMethod method) { - assert method != null; + public MethodPointer(ResolvedJavaMethod method) { + Objects.requireNonNull(method); this.method = method; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java index f0beb60ca92b..a1d599865ec4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java @@ -28,8 +28,11 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; +import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaField; @@ -50,4 +53,16 @@ public boolean isFinalField(ResolvedJavaField field, ConstantFieldTool tool) } return super.isFinalField(field, tool); } + + @Override + protected boolean isFinalFieldValueConstant(ResolvedJavaField field, JavaConstant value, ConstantFieldTool tool) { + if (value.getJavaKind() == JavaKind.Object && SubstrateObjectConstant.asObject(value) instanceof MethodPointer) { + /* + * Prevent the constant folding of MethodPointer objects. MethodPointer is a "hosted" + * type, so it cannot be present in compiler graphs. + */ + return false; + } + return super.isFinalFieldValueConstant(field, value, tool); + } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java index 4430e2cf2e0a..c4fd6a6496f4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java @@ -62,7 +62,8 @@ import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.results.AbstractAnalysisResultsBuilder; -import com.oracle.svm.core.InvalidVTableEntryHandler; +import com.oracle.svm.core.FunctionPointerHolder; +import com.oracle.svm.core.InvalidMethodPointerHandler; import com.oracle.svm.core.StaticFieldsSupport; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; @@ -70,7 +71,6 @@ import com.oracle.svm.core.annotate.ExcludeFromReferenceMap; import com.oracle.svm.core.c.BoxedRelocatedPointer; import com.oracle.svm.core.c.function.CFunctionOptions; -import com.oracle.svm.core.classinitialization.ClassInitializationInfo.ClassInitializerFunctionPointerHolder; import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.config.ObjectLayout; import com.oracle.svm.core.deopt.DeoptimizedFrame; @@ -367,7 +367,7 @@ private void buildProfilingInformation() { DynamicHub.class, CEntryPointLiteral.class, BoxedRelocatedPointer.class, - ClassInitializerFunctionPointerHolder.class, + FunctionPointerHolder.class, FillerObject.class)); static { @@ -674,7 +674,7 @@ private void buildVTables() { * To avoid segfaults when jumping to address 0, all unused vtable entries are filled with a * stub that reports a fatal error. */ - HostedMethod invalidVTableEntryHandler = hMetaAccess.lookupJavaMethod(InvalidVTableEntryHandler.HANDLER_METHOD); + HostedMethod invalidVTableEntryHandler = hMetaAccess.lookupJavaMethod(InvalidMethodPointerHandler.INVALID_VTABLE_ENTRY_HANDLER_METHOD); for (HostedType type : hUniverse.getTypes()) { if (type.isArray()) { @@ -925,7 +925,7 @@ private void buildHubs() { * We install a CodePointer in the vtable; when generating relocation info, we will * know these point into .text */ - vtable[idx] = MethodPointer.factory(type.vtable[idx]); + vtable[idx] = new MethodPointer(type.vtable[idx]); } // pointer maps in Dynamic Hub @@ -999,6 +999,6 @@ final class InvalidVTableEntryFeature implements Feature { @Override public void beforeAnalysis(BeforeAnalysisAccess a) { BeforeAnalysisAccessImpl access = (BeforeAnalysisAccessImpl) a; - access.registerAsCompiled(InvalidVTableEntryHandler.HANDLER_METHOD); + access.registerAsCompiled(InvalidMethodPointerHandler.INVALID_VTABLE_ENTRY_HANDLER_METHOD); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/option/HostedOptionParser.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/option/HostedOptionParser.java index d3cc32ea3c04..46fa77d41fa6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/option/HostedOptionParser.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/option/HostedOptionParser.java @@ -24,20 +24,19 @@ */ package com.oracle.svm.hosted.option; -import static com.oracle.svm.core.option.SubstrateOptionsParser.BooleanOptionFormat.PLUS_MINUS; +import static com.oracle.svm.common.option.CommonOptionParser.BooleanOptionFormat.PLUS_MINUS; import static com.oracle.svm.core.util.VMError.shouldNotReachHere; -import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.ServiceLoader; import java.util.Set; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.options.OptionDescriptor; import org.graalvm.compiler.options.OptionDescriptors; -import org.graalvm.compiler.options.OptionDescriptorsMap; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; import org.graalvm.nativeimage.Platforms; @@ -47,7 +46,6 @@ import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.core.util.InterruptImageBuilding; import com.oracle.svm.core.util.UserError; -import com.oracle.svm.hosted.ImageClassLoader; public class HostedOptionParser implements HostedOptionProvider { @@ -56,48 +54,36 @@ public class HostedOptionParser implements HostedOptionProvider { private EconomicMap allHostedOptions = EconomicMap.create(); private EconomicMap allRuntimeOptions = EconomicMap.create(); - public HostedOptionParser(ImageClassLoader imageClassLoader) { - collectOptions(imageClassLoader.findSubclasses(OptionDescriptors.class, true), allHostedOptions, allRuntimeOptions); + public HostedOptionParser(ClassLoader imageClassLoader) { + collectOptions(ServiceLoader.load(OptionDescriptors.class, imageClassLoader), allHostedOptions, allRuntimeOptions); } - public static void collectOptions(List> optionsClasses, EconomicMap allHostedOptions, + public static void collectOptions(ServiceLoader optionDescriptors, EconomicMap allHostedOptions, EconomicMap allRuntimeOptions) { - for (Class optionsClass : optionsClasses) { - if (Modifier.isAbstract(optionsClass.getModifiers()) || OptionDescriptorsMap.class.isAssignableFrom(optionsClass)) { - continue; - } + SubstrateOptionsParser.collectOptions(optionDescriptors, descriptor -> { + String name = descriptor.getName(); - OptionDescriptors descriptors; - try { - descriptors = optionsClass.getDeclaredConstructor().newInstance(); - } catch (Exception ex) { - throw shouldNotReachHere(ex); + if (descriptor.getDeclaringClass().getAnnotation(Platforms.class) != null) { + throw UserError.abort("Options must not be declared in a class that has a @%s annotation: option %s declared in %s", + Platforms.class.getSimpleName(), name, descriptor.getDeclaringClass().getTypeName()); } - for (OptionDescriptor descriptor : descriptors) { - String name = descriptor.getName(); - - if (descriptor.getDeclaringClass().getAnnotation(Platforms.class) != null) { - throw UserError.abort("Options must not be declared in a class that has a @%s annotation: option %s declared in %s", - Platforms.class.getSimpleName(), name, descriptor.getDeclaringClass().getTypeName()); - } - if (!(descriptor.getOptionKey() instanceof RuntimeOptionKey)) { - OptionDescriptor existing = allHostedOptions.put(name, descriptor); - if (existing != null) { - throw shouldNotReachHere("Option name \"" + name + "\" has multiple definitions: " + existing.getLocation() + " and " + descriptor.getLocation()); - } + if (!(descriptor.getOptionKey() instanceof RuntimeOptionKey)) { + OptionDescriptor existing = allHostedOptions.put(name, descriptor); + if (existing != null) { + throw shouldNotReachHere("Option name \"" + name + "\" has multiple definitions: " + existing.getLocation() + " and " + descriptor.getLocation()); } - if (!(descriptor.getOptionKey() instanceof HostedOptionKey)) { - OptionDescriptor existing = allRuntimeOptions.put(name, descriptor); - if (existing != null) { - throw shouldNotReachHere("Option name \"" + name + "\" has multiple definitions: " + existing.getLocation() + " and " + descriptor.getLocation()); - } + } + if (!(descriptor.getOptionKey() instanceof HostedOptionKey)) { + OptionDescriptor existing = allRuntimeOptions.put(name, descriptor); + if (existing != null) { + throw shouldNotReachHere("Option name \"" + name + "\" has multiple definitions: " + existing.getLocation() + " and " + descriptor.getLocation()); } } - } + }); } - public String[] parse(String[] args) { + public List parse(List args) { List remainingArgs = new ArrayList<>(); Set errors = new HashSet<>(); @@ -136,7 +122,7 @@ public String[] parse(String[] args) { } } - return remainingArgs.toArray(new String[remainingArgs.size()]); + return remainingArgs; } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/DevirtualizeCallsPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/DevirtualizeCallsPhase.java index c93bc3c9bc13..275e8d6219ef 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/DevirtualizeCallsPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/DevirtualizeCallsPhase.java @@ -111,7 +111,7 @@ private void unreachableInvoke(StructuredGraph graph, Invoke invoke, SubstrateMe String message = String.format("The call to %s is not reachable when called from %s.%n", targetMethod.format("%H.%n(%P)"), graph.method().format("%H.%n(%P)")); AnalysisSpeculation speculation = new AnalysisSpeculation(new AnalysisSpeculationReason(message)); FixedGuardNode node = new FixedGuardNode(LogicConstantNode.forBoolean(true, graph), DeoptimizationReason.UnreachedCode, DeoptimizationAction.None, speculation, true); - graph.addBeforeFixed(invoke.asNode(), graph.add(node)); + graph.addBeforeFixed(invoke.asFixedNode(), graph.add(node)); graph.getDebug().dump(DebugContext.VERY_DETAILED_LEVEL, graph, "After dead invoke %s", invoke); } @@ -136,7 +136,7 @@ private void singleCallee(HostedMethod singleCallee, StructuredGraph graph, Invo * anchor the receiver to the place of the original invoke. */ ValueAnchorNode anchor = graph.add(new ValueAnchorNode(null)); - graph.addBeforeFixed(invoke.asNode(), anchor); + graph.addBeforeFixed(invoke.asFixedNode(), anchor); Stamp anchoredReceiverStamp = StampFactory.object(TypeReference.createWithoutAssumptions(singleCallee.getDeclaringClass())); ValueNode anchoredReceiver = graph.unique(new PiNode(invoke.getReceiver(), anchoredReceiverStamp, anchor)); invoke.callTarget().replaceFirstInput(invoke.getReceiver(), anchoredReceiver); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphBuilderPhase.java index 71dc12af52ee..db05e96f5d4b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphBuilderPhase.java @@ -108,7 +108,7 @@ protected boolean stampFromValueForForcedPhis() { } @Override - public boolean disallowDeoptInPlugins() { + public boolean allowDeoptInPlugins() { return false; } @@ -212,7 +212,7 @@ private void insertDeoptNode(HostedBciBlockMapping.DeoptEntryInsertionPoint deop FrameState stateAfter = frameState.create(deopt.frameStateBci(), deoptNode); deoptNode.setStateAfter(stateAfter); if (lastInstr != null) { - lastInstr.setNext(deoptNode.asNode()); + lastInstr.setNext(deoptNode.asFixedNode()); } if (deopt.isProxy()) { @@ -261,7 +261,7 @@ private void insertDeoptNode(HostedBciBlockMapping.DeoptEntryInsertionPoint deop lastInstr = deoptEntryNode.next(); } - insertProxies(deoptNode.asNode(), frameState); + insertProxies(deoptNode.asFixedNode(), frameState); } private void insertProxies(FixedNode deoptTarget, FrameStateBuilder state) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ImplicitAssertionsPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ImplicitAssertionsPhase.java index dae23c897b7c..14169e0e815f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ImplicitAssertionsPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ImplicitAssertionsPhase.java @@ -130,14 +130,14 @@ private static void tryOptimize(StructuredGraph graph, Invoke constructorInvoke, } else if (usagesToDelete.contains(exceptionUsage)) { /* Frame state between constructor and allocation. */ } else if (exceptionUsage instanceof UnwindNode) { - if (!hasSimpleControlFlow(exceptionUsage, constructorInvoke.asNode(), null)) { + if (!hasSimpleControlFlow(exceptionUsage, constructorInvoke.asFixedNode(), null)) { /* No simple control flow path found to the UnwindNode. */ return; } } else if (exceptionUsage instanceof PhiNode) { PhiNode phi = (PhiNode) exceptionUsage; for (int i = 0; i < phi.valueCount(); i++) { - if (phi.valueAt(i) == exceptionAllocation && !hasSimpleControlFlow(phi.merge().phiPredecessorAt(i), constructorInvoke.asNode(), null)) { + if (phi.valueAt(i) == exceptionAllocation && !hasSimpleControlFlow(phi.merge().phiPredecessorAt(i), constructorInvoke.asFixedNode(), null)) { /* No simple control flow path found to the PhiNode. */ return; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java index d591f8808cf2..49a6257cee21 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java @@ -104,6 +104,8 @@ import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.graal.pointsto.meta.AnalysisUniverse; +import com.oracle.graal.pointsto.phases.NoClassInitializationPlugin; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.SubstrateOptions; @@ -117,7 +119,6 @@ import com.oracle.svm.hosted.NativeImageOptions; import com.oracle.svm.hosted.NativeImageUtil; import com.oracle.svm.hosted.SVMHost; -import com.oracle.svm.hosted.c.GraalAccess; import com.oracle.svm.hosted.meta.HostedType; import com.oracle.svm.hosted.meta.HostedUniverse; import com.oracle.svm.hosted.snippets.IntrinsificationPluginRegistry; @@ -756,7 +757,7 @@ private boolean fixedWithNextNode(FixedNode oNode) throws AbortTransplantExcepti } else if (oNode.getClass() == NewArrayNode.class) { NewArrayNode oNew = (NewArrayNode) oNode; - NewArrayNode tNew = b.add(new NewArrayNode(lookup(oNew.elementType()), node(oNew.length()), oNew.fillContents())); + NewArrayNode tNew = b.add(new NewArrayNode(lookup(oNew.elementType()), b.maybeEmitExplicitNegativeArraySizeCheck(node(oNew.length())), oNew.fillContents())); transplanted.put(oNew, tNew); return true; @@ -848,7 +849,14 @@ private void transplantInvoke(FixedWithNextNode oNode, ResolvedJavaMethod tTarge * situation, it is necessary to push the NewInstanceNode onto the stack so that it * is included in the stateDuring FrameState of the InvokeNode. */ - Node pred = oNode.predecessor(); + Node pred = oNode; + do { + pred = pred.predecessor(); + /* + * The prior NewInstanceNode may be guarded by a fixed guard (e.g., for an + * instanceof check). In this case, look at fixed guard's predecessor. + */ + } while (pred.getClass() == FixedGuardNode.class); if (pred.getClass() == NewInstanceNode.class && transplanted.containsKey(pred)) { Node tNew = transplanted.get(pred); pushToFrameStack((ValueNode) tNew); @@ -872,7 +880,7 @@ private void transplantInvoke(FixedWithNextNode oNode, ResolvedJavaMethod tTarge @SuppressWarnings("unchecked") private T stamp(T oStamp) throws AbortTransplantException { Stamp result; - if (((Stamp) oStamp).getClass() == ObjectStamp.class) { + if (oStamp.getClass() == ObjectStamp.class) { ObjectStamp oObjectStamp = (ObjectStamp) oStamp; result = new ObjectStamp(lookup(oObjectStamp.type()), oObjectStamp.isExactType(), oObjectStamp.nonNull(), oObjectStamp.alwaysNull(), oObjectStamp.isAlwaysArray()); } else if (oStamp instanceof PrimitiveStamp) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ImplicitExceptionsFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ImplicitExceptionsFeature.java index 46ac9324b928..404e9117e3bb 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ImplicitExceptionsFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ImplicitExceptionsFeature.java @@ -25,9 +25,11 @@ package com.oracle.svm.hosted.snippets; import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.core.graal.GraalFeature; import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider; +import com.oracle.svm.core.graal.snippets.NonSnippetLowerings; import com.oracle.svm.core.snippets.ExceptionUnwind; import com.oracle.svm.core.snippets.ImplicitExceptions; import com.oracle.svm.core.snippets.SnippetRuntime.SubstrateForeignCallDescriptor; @@ -46,11 +48,17 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { for (SubstrateForeignCallDescriptor descriptor : ExceptionUnwind.FOREIGN_CALLS) { access.getBigBang().addRootMethod((AnalysisMethod) descriptor.findMethod(access.getMetaAccess())); } + if (SubstrateOptions.VerifyTypes.getValue()) { + access.getBigBang().addRootMethod((AnalysisMethod) NonSnippetLowerings.REPORT_VERIFY_TYPES_ERROR.findMethod(access.getMetaAccess())); + } } @Override public void registerForeignCalls(SubstrateForeignCallsProvider foreignCalls) { foreignCalls.register(ImplicitExceptions.FOREIGN_CALLS); foreignCalls.register(ExceptionUnwind.FOREIGN_CALLS); + if (SubstrateOptions.VerifyTypes.getValue()) { + foreignCalls.register(NonSnippetLowerings.REPORT_VERIFY_TYPES_ERROR); + } } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java index 054967f7a780..76d3f034db33 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java @@ -39,6 +39,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -59,16 +60,17 @@ import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.graal.pointsto.meta.AnalysisUniverse; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.TypeResult; import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.hub.PredefinedClassesSupport; +import com.oracle.svm.core.jdk.StackTraceUtils; import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ExceptionSynthesizer; import com.oracle.svm.hosted.ImageClassLoader; -import com.oracle.svm.hosted.c.GraalAccess; import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor; import com.oracle.svm.hosted.substitute.DeletedElementException; import com.oracle.svm.util.ModuleSupport; @@ -199,6 +201,11 @@ private void registerMethodHandlesPlugins(InvocationPlugins plugins) { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { return processMethodHandlesLookup(b, targetMethod); } + + @Override + public boolean inlineOnly() { + return true; + } }); } @@ -247,6 +254,14 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec private boolean processMethodHandlesLookup(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { Supplier targetParameters = () -> ""; + if (StackTraceUtils.ignoredBySecurityStackWalk(b.getMetaAccess(), b.getMethod())) { + /* + * If our immediate caller (which is the only method available at the time the + * invocation plugin is running) is not the method returned by + * Reflection.getCallerClass(), we cannot intrinsify. + */ + return false; + } Class callerClass = OriginalClassProvider.getJavaClass(snippetReflection, b.getMethod().getDeclaringClass()); MethodHandles.Lookup lookup; try { @@ -382,7 +397,7 @@ private boolean foldInvocationUsingReflection(GraphBuilderContext b, ResolvedJav /* String representation of the parameters for debug printing. */ Supplier targetParameters = () -> (receiverValue == null ? "" : receiverValue.toString() + "; ") + - Stream.of(argValues).map(arg -> arg instanceof Object[] ? Arrays.toString((Object[]) arg) : arg.toString()).collect(Collectors.joining(", ")); + Stream.of(argValues).map(arg -> arg instanceof Object[] ? Arrays.toString((Object[]) arg) : Objects.toString(arg)).collect(Collectors.joining(", ")); Object returnValue; try { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java index 7653a2be1f22..51d43b845b1f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java @@ -56,7 +56,6 @@ import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.PiNode; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.calc.IntegerLessThanNode; import org.graalvm.compiler.nodes.calc.NarrowNode; import org.graalvm.compiler.nodes.calc.ZeroExtendNode; import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode; @@ -378,20 +377,21 @@ static Class[] extractClassArray(AnnotationSubstitutionProcessor annotationSu } while (successor instanceof StoreIndexedNode) { StoreIndexedNode store = (StoreIndexedNode) successor; - assert getDeoptProxyOriginalValue(store.array()).equals(newArray); - ValueNode valueNode = store.value(); - if (valueNode.isConstant() && !valueNode.isNullConstant()) { - Class clazz = snippetReflection.asObject(Class.class, valueNode.asJavaConstant()); - /* - * It is possible that the returned class is a substitution class, e.g., - * DynamicHub returned for a Class.class constant. Get the target class of the - * substitution class. - */ - classList.add(annotationSubstitutions == null ? clazz : annotationSubstitutions.getTargetClass(clazz)); - } else { - /* If not all classes are non-null constants we bail out. */ - classList = null; - break; + if (getDeoptProxyOriginalValue(store.array()).equals(newArray)) { + ValueNode valueNode = store.value(); + if (valueNode.isConstant() && !valueNode.isNullConstant()) { + Class clazz = snippetReflection.asObject(Class.class, valueNode.asJavaConstant()); + /* + * It is possible that the returned class is a substitution class, e.g., + * DynamicHub returned for a Class.class constant. Get the target class of + * the substitution class. + */ + classList.add(annotationSubstitutions == null ? clazz : annotationSubstitutions.getTargetClass(clazz)); + } else { + /* If not all classes are non-null constants we bail out. */ + classList = null; + break; + } } successor = unwrapNode(store.next()); } @@ -553,19 +553,22 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec * constant. That also allows us to constant-fold the required check that the * component type is a primitive type. */ - if (componentTypeNode.isJavaConstant() && componentTypeNode.asJavaConstant().isNonNull()) { - ResolvedJavaType componentType = b.getConstantReflection().asJavaType(componentTypeNode.asJavaConstant()); - if (componentType.isPrimitive()) { - /* Emits a null-check for the otherwise unused receiver. */ - unsafe.get(); - - LogicNode lengthNegative = b.append(IntegerLessThanNode.create(lengthNode, ConstantNode.forInt(0), NodeView.DEFAULT)); - b.emitBytecodeExceptionCheck(lengthNegative, false, BytecodeExceptionNode.BytecodeExceptionKind.ILLEGAL_ARGUMENT_EXCEPTION_NEGATIVE_LENGTH); - b.addPush(JavaKind.Object, new NewArrayNode(componentType, lengthNode, false)); - return true; - } + if (!componentTypeNode.isJavaConstant() || componentTypeNode.asJavaConstant().isNull()) { + return false; } - return false; + ResolvedJavaType componentType = b.getConstantReflection().asJavaType(componentTypeNode.asJavaConstant()); + if (componentType == null || !componentType.isPrimitive()) { + return false; + } + /* Emits a null-check for the otherwise unused receiver. */ + unsafe.get(); + /* + * Note that allocateUninitializedArray must throw a IllegalArgumentException, + * and not a NegativeArraySizeException, when the length is negative. + */ + ValueNode lengthPositive = b.maybeEmitExplicitNegativeArraySizeCheck(lengthNode, BytecodeExceptionNode.BytecodeExceptionKind.ILLEGAL_ARGUMENT_EXCEPTION_NEGATIVE_LENGTH); + b.addPush(JavaKind.Object, new NewArrayNode(componentType, lengthPositive, false)); + return true; } }); } @@ -666,7 +669,7 @@ private static boolean isValidField(Field targetField, boolean isSunMiscUnsafe) /* A NullPointerException will be thrown at run time for this call. */ return false; } - if (isSunMiscUnsafe && JavaVersionUtil.JAVA_SPEC >= 16 && + if (isSunMiscUnsafe && JavaVersionUtil.JAVA_SPEC >= 17 && (RecordSupport.singleton().isRecord(targetField.getDeclaringClass()) || SubstrateUtil.isHiddenClass(targetField.getDeclaringClass()))) { /* * After JDK 11, sun.misc.Unsafe performs a few more checks than diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java index 7c5d68a4b897..37a1af797f1b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java @@ -29,10 +29,10 @@ import java.util.Arrays; import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.annotate.InjectAccessors; import com.oracle.svm.core.meta.ReadableJavaField; -import com.oracle.svm.hosted.c.GraalAccess; import com.oracle.svm.util.ClassUtil; import jdk.vm.ci.meta.JavaConstant; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedMethod.java index efb3761b19f9..873cb69b7c4f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedMethod.java @@ -38,9 +38,9 @@ import com.oracle.graal.pointsto.infrastructure.GraphProvider; import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; import com.oracle.graal.pointsto.meta.HostedProviders; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.annotate.AnnotateOriginal; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.c.GraalAccess; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantPool; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java index 4837c9c75d1e..756fab20323b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java @@ -819,11 +819,13 @@ private static boolean isIncluded(TargetElement targetElementAnnotation, Class void register(Map substitutions, T annotated, T original, T target) { if (annotated != null) { - guarantee(!substitutions.containsKey(annotated) || substitutions.get(annotated) == original || substitutions.get(annotated) == target, "Already registered: %s", annotated); + guarantee(!substitutions.containsKey(annotated) || substitutions.get(annotated) == original || substitutions.get(annotated) == target, + "Substition: %s conflicts with previously registered: %s", annotated, substitutions.get(annotated)); substitutions.put(annotated, target); } if (original != null) { - guarantee(!substitutions.containsKey(original) || substitutions.get(original) == original || substitutions.get(original) == target, "Already registered: %s", original); + guarantee(!substitutions.containsKey(original) || substitutions.get(original) == original || substitutions.get(original) == target, + "Substition: %s conflicts with previously registered: %s", original, substitutions.get(original)); substitutions.put(original, target); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java index fa3b5f9fc3f3..86ad7c4c4bc6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java @@ -44,6 +44,7 @@ import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.RecomputeFieldValue.CustomFieldValueComputer; import com.oracle.svm.core.annotate.RecomputeFieldValue.CustomFieldValueTransformer; @@ -51,7 +52,6 @@ import com.oracle.svm.core.meta.ReadableJavaField; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.c.GraalAccess; import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedMetaAccess; import com.oracle.svm.util.ReflectionUtil; @@ -236,12 +236,43 @@ public JavaConstant readValue(MetaAccessProvider metaAccess, JavaConstant receiv return constantValue; } - JavaConstant result = getCached(receiver); - if (result != null) { + ReadLock readLock = valueCacheLock.readLock(); + try { + readLock.lock(); + JavaConstant result = getCached(receiver); + if (result != null) { + return result; + } + } finally { + readLock.unlock(); + } + + WriteLock writeLock = valueCacheLock.writeLock(); + try { + writeLock.lock(); + /* + * Check the cache again, now that we are holding the write-lock, i.e., we know that no + * other thread is computing a value right now. + */ + JavaConstant result = getCached(receiver); + if (result != null) { + return result; + } + /* + * Note that the value computation must be inside the lock, because we want to guarantee + * that field-value computers are only executed once per unique receiver. + */ + result = computeValue(metaAccess, receiver); + putCached(receiver, result); return result; + } finally { + writeLock.unlock(); } + } + private JavaConstant computeValue(MetaAccessProvider metaAccess, JavaConstant receiver) { SnippetReflectionProvider originalSnippetReflection = GraalAccess.getOriginalSnippetReflection(); + JavaConstant result; switch (kind) { case NewInstance: try { @@ -296,9 +327,10 @@ public JavaConstant readValue(MetaAccessProvider metaAccess, JavaConstant receiv } break; default: - throw shouldNotReachHere("Field recomputation of kind " + kind + " specified by alias " + annotated.format("%H.%n") + " not yet supported"); + throw shouldNotReachHere("Field recomputation of kind " + kind + " for field " + original.format("%H.%n") + + (annotated != null ? " specified by alias " + annotated.format("%H.%n") : "") + + " not yet supported"); } - putCached(receiver, result); return result; } @@ -306,33 +338,19 @@ private void putCached(JavaConstant receiver, JavaConstant result) { if (disableCaching) { return; } - WriteLock writeLock = valueCacheLock.writeLock(); - try { - writeLock.lock(); - if (receiver == null) { - valueCacheNullKey = result; - } else { - valueCache.put(receiver, result); - } - } finally { - writeLock.unlock(); + if (receiver == null) { + valueCacheNullKey = result; + } else { + valueCache.put(receiver, result); } } private JavaConstant getCached(JavaConstant receiver) { - JavaConstant result; - ReadLock readLock = valueCacheLock.readLock(); - try { - readLock.lock(); - if (receiver == null) { - result = valueCacheNullKey; - } else { - result = valueCache.get(receiver); - } - } finally { - readLock.unlock(); + if (receiver == null) { + return valueCacheNullKey; + } else { + return valueCache.get(receiver); } - return result; } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/InjectedAccessorsField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/InjectedAccessorsField.java index 3ed62d84f6fa..281c1d33877d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/InjectedAccessorsField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/InjectedAccessorsField.java @@ -29,10 +29,10 @@ import java.util.Arrays; import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.annotate.InjectAccessors; import com.oracle.svm.core.meta.ReadableJavaField; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.c.GraalAccess; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaType; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/InjectedFieldsType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/InjectedFieldsType.java index 4af972e84e4e..4620cb2bf8a4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/InjectedFieldsType.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/InjectedFieldsType.java @@ -28,7 +28,7 @@ import java.util.Arrays; import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; -import com.oracle.svm.hosted.c.GraalAccess; +import com.oracle.graal.pointsto.util.GraalAccess; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.Assumptions.AssumptionResult; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java index 23a7b1beca8b..54c2d365a718 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java @@ -28,8 +28,8 @@ import java.lang.reflect.Field; import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.meta.ReadableJavaField; -import com.oracle.svm.hosted.c.GraalAccess; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaType; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionMethod.java index b28fc46cb0df..d66751657378 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionMethod.java @@ -37,7 +37,7 @@ import com.oracle.graal.pointsto.infrastructure.GraphProvider; import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; import com.oracle.graal.pointsto.meta.HostedProviders; -import com.oracle.svm.hosted.c.GraalAccess; +import com.oracle.graal.pointsto.util.GraalAccess; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantPool; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionType.java index 4c70180a5e66..a3f3d336b96e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionType.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionType.java @@ -29,7 +29,7 @@ import java.util.Arrays; import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; -import com.oracle.svm.hosted.c.GraalAccess; +import com.oracle.graal.pointsto.util.GraalAccess; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.Assumptions.AssumptionResult; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/UnsafeAutomaticSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/UnsafeAutomaticSubstitutionProcessor.java index 54372b325283..996e30b68b2e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/UnsafeAutomaticSubstitutionProcessor.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/UnsafeAutomaticSubstitutionProcessor.java @@ -74,6 +74,8 @@ import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.phases.NoClassInitializationPlugin; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.AutomaticFeature; @@ -85,9 +87,7 @@ import com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl; import com.oracle.svm.hosted.ImageClassLoader; import com.oracle.svm.hosted.SVMHost; -import com.oracle.svm.hosted.c.GraalAccess; import com.oracle.svm.hosted.classinitialization.ClassInitializerGraphBuilderPhase; -import com.oracle.svm.hosted.phases.NoClassInitializationPlugin; import com.oracle.svm.hosted.snippets.ReflectionPlugins; import jdk.vm.ci.meta.JavaKind; @@ -214,9 +214,9 @@ public void init(ImageClassLoader loader, MetaAccessProvider originalMetaAccess) neverInlineSet.add(unsafeObjectFieldOffsetClassStringMethod); } - if (JavaVersionUtil.JAVA_SPEC >= 15) { + if (JavaVersionUtil.JAVA_SPEC >= 17) { /* - * JDK 15 and later add checks for hidden classes and record classes in + * JDK 17 and later add checks for hidden classes and record classes in * sun.misc.Unsafe before delegating to jdk.internal.misc.Unsafe. When inlined, the * checks make control flow too complex to detect offset field assignments. */ @@ -426,7 +426,7 @@ private boolean isValidField(Invoke invoke, Field field, List unsuccessf } boolean valid = true; - if (JavaVersionUtil.JAVA_SPEC >= 15 && isInvokeTo(invoke, sunMiscUnsafeObjectFieldOffsetMethod)) { + if (JavaVersionUtil.JAVA_SPEC >= 17 && isInvokeTo(invoke, sunMiscUnsafeObjectFieldOffsetMethod)) { Class declaringClass = field.getDeclaringClass(); if (RecordSupport.singleton().isRecord(declaringClass)) { unsuccessfulReasons.add("The argument to sun.misc.Unsafe.objectFieldOffset(Field) is a field of a record."); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadLocalCollector.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadLocalCollector.java index 2c709b5aa467..6850a186cb57 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadLocalCollector.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadLocalCollector.java @@ -36,17 +36,11 @@ import org.graalvm.compiler.nodes.PiNode; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; -import org.graalvm.nativeimage.hosted.Feature; import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.threadlocal.FastThreadLocal; import com.oracle.svm.core.threadlocal.VMThreadLocalInfo; -import com.oracle.svm.hosted.FeatureImpl.CompilationAccessImpl; -import com.oracle.svm.hosted.meta.HostedField; - -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaField; /** * Collects all {@link FastThreadLocal} instances that are actually used by the application. @@ -90,37 +84,9 @@ public VMThreadLocalInfo findInfo(GraphBuilderContext b, ValueNode threadLocalNo return result; } - public List sortThreadLocals(Feature.CompilationAccess a) { - CompilationAccessImpl config = (CompilationAccessImpl) a; - + public List sortThreadLocals() { sealed = true; - - /* - * Find a unique static field for every VM thread local object. The field name is used to - * make the layout of VMThread deterministic. - */ - for (ResolvedJavaField f : config.getFields()) { - HostedField field = (HostedField) f; - if (field.isStatic() && field.getStorageKind() == JavaKind.Object) { - Object fieldValue = SubstrateObjectConstant.asObject(field.readValue(null)); - if (fieldValue instanceof FastThreadLocal) { - FastThreadLocal threadLocal = (FastThreadLocal) fieldValue; - VMThreadLocalInfo info = threadLocals.get(threadLocal); - String fieldName = field.format("%H.%n"); - if (!field.isFinal()) { - throw shouldNotReachHere("VMThreadLocal referenced from non-final field: " + fieldName); - } else if (info.name != null) { - throw shouldNotReachHere("VMThreadLocal referenced from two static final fields: " + info.name + ", " + fieldName); - } - info.name = fieldName; - } - } - } for (VMThreadLocalInfo info : threadLocals.values()) { - if (info.name == null) { - shouldNotReachHere("VMThreadLocal found that is not referenced from a static final field"); - } - assert info.sizeInBytes == -1; if (info.sizeSupplier != null) { int unalignedSize = info.sizeSupplier.getAsInt(); @@ -158,7 +124,6 @@ private static int compareThreadLocal(VMThreadLocalInfo info1, VMThreadLocalInfo } } } - assert result != 0 : "not distinguishable: " + info1 + ", " + info2; return result; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadMTFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadMTFeature.java index aecf007945d6..815d2acefc0e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadMTFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadMTFeature.java @@ -238,7 +238,7 @@ public void duringAnalysis(DuringAnalysisAccess access) { @Override public void beforeCompilation(BeforeCompilationAccess config) { - List sortedThreadLocalInfos = threadLocalCollector.sortThreadLocals(config); + List sortedThreadLocalInfos = threadLocalCollector.sortThreadLocals(); SubstrateReferenceMap referenceMap = new SubstrateReferenceMap(); int nextOffset = 0; for (VMThreadLocalInfo info : sortedThreadLocalInfos) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadSTFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadSTFeature.java index e585700d56c4..13ec85cf0ca4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadSTFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadSTFeature.java @@ -217,7 +217,7 @@ public void duringAnalysis(DuringAnalysisAccess access) { @Override public void beforeCompilation(BeforeCompilationAccess config) { - List sortedThreadLocalInfos = threadLocalCollector.sortThreadLocals(config); + List sortedThreadLocalInfos = threadLocalCollector.sortThreadLocals(); ObjectLayout layout = ConfigurationValues.getObjectLayout(); int nextObject = 0; int nextPrimitive = 0; diff --git a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrEnabled.java b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrEnabled.java index cfa97353c7a0..e491abd834d1 100644 --- a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrEnabled.java +++ b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrEnabled.java @@ -45,8 +45,9 @@ public static boolean get() { } private static boolean jvmVersionSupported() { - return JavaVersionUtil.JAVA_SPEC == 11 || JavaVersionUtil.JAVA_SPEC == 16 || JavaVersionUtil.JAVA_SPEC == 17; + return JavaVersionUtil.JAVA_SPEC >= 11; } + private static boolean osSupported() { return OS.getCurrent() == OS.LINUX || OS.getCurrent() == OS.DARWIN; } diff --git a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrEventSubstitution.java b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrEventSubstitution.java index b44f203846d1..776913eeab95 100644 --- a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrEventSubstitution.java +++ b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrEventSubstitution.java @@ -37,8 +37,8 @@ import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.c.GraalAccess; import jdk.jfr.Event; import jdk.jfr.internal.EventWriter; diff --git a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrSymbolRepository.java b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrSymbolRepository.java index a1f82973ebc7..56ebfe597881 100644 --- a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrSymbolRepository.java +++ b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrSymbolRepository.java @@ -125,7 +125,7 @@ public int write(JfrChunkWriter writer) { return 1; } - private void writeSymbol(JfrChunkWriter writer, JfrSymbol symbol) { + private static void writeSymbol(JfrChunkWriter writer, JfrSymbol symbol) { writer.writeCompressedLong(symbol.getId()); writer.writeByte(JfrChunkWriter.StringEncoding.UTF8_BYTE_ARRAY.byteValue); byte[] value = symbol.getValue().getBytes(StandardCharsets.UTF_8); @@ -136,7 +136,7 @@ private void writeSymbol(JfrChunkWriter writer, JfrSymbol symbol) { writer.writeBytes(value); } - private void replaceDotWithSlash(byte[] utf8String) { + private static void replaceDotWithSlash(byte[] utf8String) { for (int i = 0; i < utf8String.length; i++) { if (utf8String[i] == '.') { utf8String[i] = '/'; diff --git a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrThreadLocal.java b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrThreadLocal.java index 0bee57ab6d75..06cac6b8d089 100644 --- a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrThreadLocal.java +++ b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrThreadLocal.java @@ -24,7 +24,6 @@ */ package com.oracle.svm.jfr; -import com.oracle.svm.core.thread.VMOperation; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.Platform; @@ -38,6 +37,7 @@ import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.thread.Target_java_lang_Thread; import com.oracle.svm.core.thread.ThreadListener; +import com.oracle.svm.core.thread.VMOperation; import com.oracle.svm.core.threadlocal.FastThreadLocalFactory; import com.oracle.svm.core.threadlocal.FastThreadLocalLong; import com.oracle.svm.core.threadlocal.FastThreadLocalObject; @@ -63,11 +63,12 @@ * modify the buffers of other threads). */ public class JfrThreadLocal implements ThreadListener { - private static final FastThreadLocalObject javaEventWriter = FastThreadLocalFactory.createObject(Target_jdk_jfr_internal_EventWriter.class); - private static final FastThreadLocalWord javaBuffer = FastThreadLocalFactory.createWord(); - private static final FastThreadLocalWord nativeBuffer = FastThreadLocalFactory.createWord(); - private static final FastThreadLocalWord dataLost = FastThreadLocalFactory.createWord(); - private static final FastThreadLocalLong traceId = FastThreadLocalFactory.createLong(); + private static final FastThreadLocalObject javaEventWriter = FastThreadLocalFactory.createObject(Target_jdk_jfr_internal_EventWriter.class, + "JfrThreadLocal.javaEventWriter"); + private static final FastThreadLocalWord javaBuffer = FastThreadLocalFactory.createWord("JfrThreadLocal.javaBuffer"); + private static final FastThreadLocalWord nativeBuffer = FastThreadLocalFactory.createWord("JfrThreadLocal.nativeBuffer"); + private static final FastThreadLocalWord dataLost = FastThreadLocalFactory.createWord("JfrThreadLocal.dataLost"); + private static final FastThreadLocalLong traceId = FastThreadLocalFactory.createLong("JfrThreadLocal.traceId"); private long threadLocalBufferSize; diff --git a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrTypeRepository.java b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrTypeRepository.java index 17ee27da460a..81221bc959ed 100644 --- a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrTypeRepository.java +++ b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrTypeRepository.java @@ -29,12 +29,13 @@ import java.util.Map; import java.util.Set; +import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; +import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.heap.Heap; -import com.oracle.svm.core.jdk.HiddenClassSupport; import com.oracle.svm.jfr.traceid.JfrTraceId; /** @@ -121,8 +122,8 @@ private static void writeClass(JfrChunkWriter writer, TypeInfo typeInfo, Class= 17) { + writer.writeBoolean(SubstrateUtil.isHiddenClass(clazz)); } } diff --git a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/SubstrateJVM.java b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/SubstrateJVM.java index 585932ec5494..68abedd6ca90 100644 --- a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/SubstrateJVM.java +++ b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/SubstrateJVM.java @@ -403,7 +403,6 @@ public boolean shouldRotateDisk() { } } - /** See {@link JVM#getChunkStartNanos}. */ public long getChunkStartNanos() { JfrChunkWriter chunkWriter = unlockedChunkWriter.lock(); try { diff --git a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/Target_jdk_jfr_internal_JVM.java b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/Target_jdk_jfr_internal_JVM.java index 2cf9121df458..48d3bbcb4d27 100644 --- a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/Target_jdk_jfr_internal_JVM.java +++ b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/Target_jdk_jfr_internal_JVM.java @@ -35,10 +35,7 @@ import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.annotate.TargetElement; import com.oracle.svm.core.jdk.JDK11OrEarlier; -import com.oracle.svm.core.jdk.JDK14OrEarlier; -import com.oracle.svm.core.jdk.JDK14OrLater; -import com.oracle.svm.core.jdk.JDK15OrLater; -import com.oracle.svm.core.jdk.JDK16OrEarlier; +import com.oracle.svm.core.jdk.JDK17OrLater; import com.oracle.svm.core.util.VMError; import com.oracle.svm.jfr.traceid.JfrTraceId; @@ -94,7 +91,7 @@ public void endRecording() { /** See {@link JVM#isRecording}. */ @Substitute - @TargetElement(onlyWith = JDK14OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) public boolean isRecording() { return SubstrateJVM.get().unsafeIsRecording(); } @@ -117,9 +114,9 @@ public static long getClassId(Class clazz) { return SubstrateJVM.get().getClassId(clazz); } - /** See {@link JVM#getClassIdNonIntrinsic}. */ + /** See JVM.getClassIdNonIntrinsic(Class). */ @Substitute - @TargetElement(onlyWith = JDK16OrEarlier.class) + @TargetElement(onlyWith = JDK11OrEarlier.class) public static long getClassIdNonIntrinsic(Class clazz) { return getClassId(clazz); } @@ -286,25 +283,24 @@ public double getTimeConversionFactor() { return 1; } - /** See {@link JVM#getChunkStartNanos}. */ + /** See {@link SubstrateJVM#getChunkStartNanos}. */ @Substitute - @TargetElement(onlyWith = JDK14OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) public long getChunkStartNanos() { return SubstrateJVM.get().getChunkStartNanos(); } - /** See {@link JVM#setHandler}. */ @Substitute - @TargetElement(onlyWith = JDK15OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) public boolean setHandler(Class eventClass, EventHandler handler) { // eventHandler fields should all be set at compile time so this method // should never be reached at runtime throw VMError.shouldNotReachHere("eventHandler does not exist for: " + eventClass); } - /** See {@link JVM#getHandler}. */ + /** See {@link SubstrateJVM#getHandler}. */ @Substitute - @TargetElement(onlyWith = JDK15OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) public Object getHandler(Class eventClass) { return SubstrateJVM.getHandler(eventClass); } @@ -360,14 +356,14 @@ public boolean setCutoff(long eventTypeId, long cutoffTicks) { /** See {@link JVM#emitOldObjectSamples}. */ @Substitute - @TargetElement(onlyWith = JDK14OrEarlier.class) // + @TargetElement(onlyWith = JDK11OrEarlier.class) // public void emitOldObjectSamples(long cutoff, boolean emitAll) { // Not supported but this method is called during JFR shutdown, so we can't throw an error. } /** See {@link JVM#emitOldObjectSamples}. */ @Substitute - @TargetElement(onlyWith = JDK15OrLater.class) // + @TargetElement(onlyWith = JDK17OrLater.class) // public void emitOldObjectSamples(long cutoff, boolean emitAll, boolean skipBFS) { // Not supported but this method is called during JFR shutdown, so we can't throw an error. } @@ -380,36 +376,32 @@ public boolean shouldRotateDisk() { /** See {@link JVM#flush}. */ @Substitute - @TargetElement(onlyWith = JDK14OrLater.class) // + @TargetElement(onlyWith = JDK17OrLater.class) // public void flush() { // Temporarily do nothing. This is used for JFR streaming. } - /** See {@link JVM#include}. */ @Substitute - @TargetElement(onlyWith = JDK14OrLater.class) // + @TargetElement(onlyWith = JDK17OrLater.class) // public void include(Thread thread) { // Temporarily do nothing. This is used for JFR streaming. } - /** See {@link JVM#exclude}. */ @Substitute - @TargetElement(onlyWith = JDK14OrLater.class) // + @TargetElement(onlyWith = JDK17OrLater.class) // public void exclude(Thread thread) { // Temporarily do nothing. This is used for JFR streaming. } - /** See {@link JVM#isExcluded}. */ @Substitute - @TargetElement(onlyWith = JDK14OrLater.class) // + @TargetElement(onlyWith = JDK17OrLater.class) // public boolean isExcluded(Thread thread) { // Temporarily do nothing. This is used for JFR streaming. return false; } - /** See {@link JVM#markChunkFinal}. */ @Substitute - @TargetElement(onlyWith = JDK14OrLater.class) // + @TargetElement(onlyWith = JDK17OrLater.class) // public void markChunkFinal() { // Temporarily do nothing. This is used for JFR streaming. } diff --git a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/logging/JfrLogConfiguration.java b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/logging/JfrLogConfiguration.java index 836ef94d2494..46efae8dcc33 100644 --- a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/logging/JfrLogConfiguration.java +++ b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/logging/JfrLogConfiguration.java @@ -112,21 +112,13 @@ private static Map> createLogTagSets() { result.put(LogTag.JFR_SETTING, EnumSet.of(JfrLogTag.JFR, JfrLogTag.SETTING)); result.put(LogTag.JFR_DCMD, EnumSet.of(JfrLogTag.JFR, JfrLogTag.DCMD)); - // JDK16 support - if (JavaVersionUtil.JAVA_SPEC >= 16) { + // JDK17 support + if (JavaVersionUtil.JAVA_SPEC >= 17) { try { LogTag jfrSystemStreaming = Enum.valueOf(LogTag.class, "JFR_SYSTEM_STREAMING"); LogTag jfrSystemThrottle = Enum.valueOf(LogTag.class, "JFR_SYSTEM_THROTTLE"); result.put(jfrSystemStreaming, EnumSet.of(JfrLogTag.JFR, JfrLogTag.SYSTEM, JfrLogTag.STREAMING)); result.put(jfrSystemThrottle, EnumSet.of(JfrLogTag.JFR, JfrLogTag.SYSTEM, JfrLogTag.THROTTLE)); - } catch (IllegalArgumentException | NullPointerException e) { - throw VMError.shouldNotReachHere("Should be defined", e); - } - } - - // JDK17 support - if (JavaVersionUtil.JAVA_SPEC >= 17) { - try { LogTag jfrStart = Enum.valueOf(LogTag.class, "JFR_START"); result.put(jfrStart, EnumSet.of(JfrLogTag.JFR, JfrLogTag.START)); } catch (IllegalArgumentException | NullPointerException e) { diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNILibraryInitializer.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNILibraryInitializer.java index 2e01394009ab..9ba751fe7934 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNILibraryInitializer.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNILibraryInitializer.java @@ -24,12 +24,17 @@ */ package com.oracle.svm.jni; -import com.oracle.svm.core.c.CGlobalData; -import com.oracle.svm.core.c.CGlobalDataFactory; -import com.oracle.svm.core.jdk.NativeLibrarySupport; -import com.oracle.svm.core.jdk.PlatformNativeLibrarySupport; -import com.oracle.svm.jni.functions.JNIFunctionTables; -import com.oracle.svm.jni.nativeapi.JNIJavaVM; +import static com.oracle.svm.jni.nativeapi.JNIVersion.JNI_VERSION_1_1; +import static com.oracle.svm.jni.nativeapi.JNIVersion.JNI_VERSION_1_2; +import static com.oracle.svm.jni.nativeapi.JNIVersion.JNI_VERSION_1_4; +import static com.oracle.svm.jni.nativeapi.JNIVersion.JNI_VERSION_1_6; +import static com.oracle.svm.jni.nativeapi.JNIVersion.JNI_VERSION_1_8; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + import org.graalvm.collections.EconomicMap; import org.graalvm.collections.Equivalence; import org.graalvm.nativeimage.c.function.CFunctionPointer; @@ -38,16 +43,13 @@ import org.graalvm.word.PointerBase; import org.graalvm.word.WordFactory; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - -import static com.oracle.svm.jni.nativeapi.JNIVersion.JNI_VERSION_1_1; -import static com.oracle.svm.jni.nativeapi.JNIVersion.JNI_VERSION_1_2; -import static com.oracle.svm.jni.nativeapi.JNIVersion.JNI_VERSION_1_4; -import static com.oracle.svm.jni.nativeapi.JNIVersion.JNI_VERSION_1_6; -import static com.oracle.svm.jni.nativeapi.JNIVersion.JNI_VERSION_1_8; +import com.oracle.svm.core.c.CGlobalData; +import com.oracle.svm.core.c.CGlobalDataFactory; +import com.oracle.svm.core.jdk.NativeLibrarySupport; +import com.oracle.svm.core.jdk.PlatformNativeLibrarySupport; +import com.oracle.svm.core.util.ImageHeapMap; +import com.oracle.svm.jni.functions.JNIFunctionTables; +import com.oracle.svm.jni.nativeapi.JNIJavaVM; interface JNIOnLoadFunctionPointer extends CFunctionPointer { @InvokeCFunctionPointer @@ -56,7 +58,7 @@ interface JNIOnLoadFunctionPointer extends CFunctionPointer { public class JNILibraryInitializer implements NativeLibrarySupport.LibraryInitializer { - private final EconomicMap> onLoadCGlobalDataMap = EconomicMap.create(Equivalence.IDENTITY); + private final EconomicMap> onLoadCGlobalDataMap = ImageHeapMap.create(Equivalence.IDENTITY); public static String getOnLoadName(String libName, boolean isBuiltIn) { String name = "JNI_OnLoad"; diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIObjectHandles.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIObjectHandles.java index 42479d409c0a..55331510b234 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIObjectHandles.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIObjectHandles.java @@ -80,7 +80,7 @@ public static T nullHandle() { static final int NATIVE_CALL_MIN_LOCAL_HANDLE_CAPACITY = 16; @SuppressWarnings("rawtypes") private static final FastThreadLocalObject handles // - = FastThreadLocalFactory.createObject(ThreadLocalHandles.class); + = FastThreadLocalFactory.createObject(ThreadLocalHandles.class, "JNIObjectHandles.handles"); @Fold static boolean useImageHeapHandles() { diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIThreadLocalEnvironment.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIThreadLocalEnvironment.java index 7c9806ce0b6e..9dc92fae76fa 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIThreadLocalEnvironment.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIThreadLocalEnvironment.java @@ -41,7 +41,8 @@ public class JNIThreadLocalEnvironment { * structure. For that reason, it has the same address as the VMThread and can be used to * restore the designated VMThread register when transitioning from native to Java. */ - static final FastThreadLocalBytes jniFunctions = FastThreadLocalFactory.createBytes(() -> SizeOf.get(JNIEnvironment.class)).setMaxOffset(0); + static final FastThreadLocalBytes jniFunctions = FastThreadLocalFactory.createBytes(() -> SizeOf.get(JNIEnvironment.class), "JNIThreadLocalEnvironment.jniFunctions") + .setMaxOffset(0); public static JNIEnvironment getAddress() { JNIEnvironment env = jniFunctions.getAddress(); diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIThreadLocalPendingException.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIThreadLocalPendingException.java index 37e1a3d427f4..fcc91a33b110 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIThreadLocalPendingException.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIThreadLocalPendingException.java @@ -31,7 +31,7 @@ * Retains one exception per thread that is pending to be handled in that thread (or none). */ public class JNIThreadLocalPendingException { - private static final FastThreadLocalObject pendingException = FastThreadLocalFactory.createObject(Throwable.class); + private static final FastThreadLocalObject pendingException = FastThreadLocalFactory.createObject(Throwable.class, "JNIThreadLocalPendingException.pendingException"); public static Throwable get() { return pendingException.get(); diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIThreadLocalPinnedObjects.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIThreadLocalPinnedObjects.java index d93e7ab170f2..9f30fc6cf3dd 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIThreadLocalPinnedObjects.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIThreadLocalPinnedObjects.java @@ -47,7 +47,8 @@ private static class PinnedObjectListNode { } } - private static final FastThreadLocalObject pinnedObjectsListHead = FastThreadLocalFactory.createObject(PinnedObjectListNode.class); + private static final FastThreadLocalObject pinnedObjectsListHead = FastThreadLocalFactory.createObject(PinnedObjectListNode.class, + "JNIThreadLocalPinnedObjects.pinnedObjectsListHead"); public static T pinArrayAndGetAddress(Object array) { PinnedObject pin = PinnedObject.create(array); diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIThreadOwnedMonitors.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIThreadOwnedMonitors.java index 83a29bda54c4..2b3e8e40550a 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIThreadOwnedMonitors.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIThreadOwnedMonitors.java @@ -36,7 +36,7 @@ public class JNIThreadOwnedMonitors { @SuppressWarnings("rawtypes") // - private static final FastThreadLocalObject ownedMonitors = FastThreadLocalFactory.createObject(IdentityHashMap.class); + private static final FastThreadLocalObject ownedMonitors = FastThreadLocalFactory.createObject(IdentityHashMap.class, "JNIThreadOwnedMonitors.ownedMonitors"); @SuppressWarnings("unchecked") private static IdentityHashMap mutableMap() { diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessibleClass.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessibleClass.java index d7ceb27e6b96..ff87a61be8c0 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessibleClass.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessibleClass.java @@ -24,15 +24,16 @@ */ package com.oracle.svm.jni.access; -import java.util.Collection; import java.util.Collections; -import java.util.HashMap; -import java.util.Map; import java.util.function.Function; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.MapCursor; import org.graalvm.nativeimage.Platform.HOSTED_ONLY; import org.graalvm.nativeimage.Platforms; +import com.oracle.svm.core.util.ImageHeapMap; + import jdk.vm.ci.meta.MetaUtil; /** @@ -40,8 +41,8 @@ */ public final class JNIAccessibleClass { private final Class classObject; - private Map methods; - private Map fields; + private EconomicMap methods; + private EconomicMap fields; JNIAccessibleClass(Class clazz) { this.classObject = clazz; @@ -51,12 +52,12 @@ public Class getClassObject() { return classObject; } - public Collection getFields() { - return (fields != null) ? fields.values() : Collections.emptySet(); + public Iterable getFields() { + return (fields != null) ? fields.getValues() : Collections::emptyIterator; } - Map getFieldsByName() { - return (fields != null) ? fields : Collections.emptyMap(); + MapCursor getFieldsByName() { + return (fields != null) ? fields.getEntries() : EconomicMap.emptyCursor(); } public JNIAccessibleField getField(String name) { @@ -66,25 +67,29 @@ public JNIAccessibleField getField(String name) { @Platforms(HOSTED_ONLY.class) void addFieldIfAbsent(String name, Function mappingFunction) { if (fields == null) { - fields = new HashMap<>(); + fields = ImageHeapMap.create(); + } + if (!fields.containsKey(name)) { + fields.put(name, mappingFunction.apply(name)); } - fields.computeIfAbsent(name, mappingFunction); } @Platforms(HOSTED_ONLY.class) void addMethodIfAbsent(JNIAccessibleMethodDescriptor descriptor, Function mappingFunction) { if (methods == null) { - methods = new HashMap<>(); + methods = ImageHeapMap.create(); + } + if (!methods.containsKey(descriptor)) { + methods.put(descriptor, mappingFunction.apply(descriptor)); } - methods.computeIfAbsent(descriptor, mappingFunction); } - public Collection getMethods() { - return (methods != null) ? methods.values() : Collections.emptySet(); + public Iterable getMethods() { + return (methods != null) ? methods.getValues() : Collections::emptyIterator; } - public Map getMethodsByDescriptor() { - return (methods != null) ? methods : Collections.emptyMap(); + public MapCursor getMethodsByDescriptor() { + return (methods != null) ? methods.getEntries() : EconomicMap.emptyCursor(); } public JNIAccessibleMethod getMethod(JNIAccessibleMethodDescriptor descriptor) { diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessibleMethod.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessibleMethod.java index adefdc5ab15d..5c85406a0397 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessibleMethod.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessibleMethod.java @@ -124,13 +124,13 @@ public boolean isStatic() { void finishBeforeCompilation(CompilationAccessImpl access) { HostedUniverse hUniverse = access.getUniverse(); AnalysisUniverse aUniverse = access.getUniverse().getBigBang().getUniverse(); - varargsCallWrapper = MethodPointer.factory(hUniverse.lookup(aUniverse.lookup(varargsCallWrapperMethod))); - arrayCallWrapper = MethodPointer.factory(hUniverse.lookup(aUniverse.lookup(arrayCallWrapperMethod))); - valistCallWrapper = MethodPointer.factory(hUniverse.lookup(aUniverse.lookup(valistCallWrapperMethod))); + varargsCallWrapper = new MethodPointer(hUniverse.lookup(aUniverse.lookup(varargsCallWrapperMethod))); + arrayCallWrapper = new MethodPointer(hUniverse.lookup(aUniverse.lookup(arrayCallWrapperMethod))); + valistCallWrapper = new MethodPointer(hUniverse.lookup(aUniverse.lookup(valistCallWrapperMethod))); if (!Modifier.isStatic(modifiers) && !Modifier.isAbstract(modifiers)) { - varargsNonvirtualCallWrapper = MethodPointer.factory(hUniverse.lookup(aUniverse.lookup(varargsNonvirtualCallWrapperMethod))); - arrayNonvirtualCallWrapper = MethodPointer.factory(hUniverse.lookup(aUniverse.lookup(arrayNonvirtualCallWrapperMethod))); - valistNonvirtualCallWrapper = MethodPointer.factory(hUniverse.lookup(aUniverse.lookup(valistNonvirtualCallWrapperMethod))); + varargsNonvirtualCallWrapper = new MethodPointer(hUniverse.lookup(aUniverse.lookup(varargsNonvirtualCallWrapperMethod))); + arrayNonvirtualCallWrapper = new MethodPointer(hUniverse.lookup(aUniverse.lookup(arrayNonvirtualCallWrapperMethod))); + valistNonvirtualCallWrapper = new MethodPointer(hUniverse.lookup(aUniverse.lookup(valistNonvirtualCallWrapperMethod))); } setHidingSubclasses(access.getMetaAccess(), this::anyMatchIgnoreReturnType); } diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIReflectionDictionary.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIReflectionDictionary.java index 596a54a85f47..e09288ec28dd 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIReflectionDictionary.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIReflectionDictionary.java @@ -27,13 +27,11 @@ import static com.oracle.svm.core.SubstrateOptions.JNIVerboseLookupErrors; import java.io.PrintStream; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; import java.util.Map; -import java.util.Map.Entry; import java.util.function.Function; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.MapCursor; import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; @@ -47,6 +45,7 @@ import com.oracle.svm.core.Isolates; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.log.Log; +import com.oracle.svm.core.util.ImageHeapMap; import com.oracle.svm.jni.nativeapi.JNIFieldId; import com.oracle.svm.jni.nativeapi.JNIMethodId; @@ -68,9 +67,9 @@ public static JNIReflectionDictionary singleton() { return ImageSingletons.lookup(JNIReflectionDictionary.class); } - private final Map classesByName = new HashMap<>(); - private final Map, JNIAccessibleClass> classesByClassObject = new HashMap<>(); - private final Map nativeLinkages = new HashMap<>(); + private final EconomicMap classesByName = ImageHeapMap.create(); + private final EconomicMap, JNIAccessibleClass> classesByClassObject = ImageHeapMap.create(); + private final EconomicMap nativeLinkages = ImageHeapMap.create(); private JNIReflectionDictionary() { } @@ -80,26 +79,30 @@ private void dump(boolean condition, String label) { PrintStream ps = Log.logStream(); ps.println(label); ps.println(" classesByName:"); - for (Map.Entry e : classesByName.entrySet()) { + MapCursor nameCursor = classesByName.getEntries(); + while (nameCursor.advance()) { ps.print(" "); - ps.println(e.getKey()); - JNIAccessibleClass clazz = e.getValue(); + ps.println(nameCursor.getKey()); + JNIAccessibleClass clazz = nameCursor.getValue(); ps.println(" methods:"); - for (Map.Entry m : clazz.getMethodsByDescriptor().entrySet()) { + MapCursor methodsCursor = clazz.getMethodsByDescriptor(); + while (methodsCursor.advance()) { ps.print(" "); - ps.println(m.getKey().getNameAndSignature()); + ps.println(methodsCursor.getKey().getNameAndSignature()); } ps.println(" fields:"); - for (Map.Entry f : clazz.getFieldsByName().entrySet()) { + MapCursor fieldsCursor = clazz.getFieldsByName(); + while (fieldsCursor.advance()) { ps.print(" "); - ps.println(f.getKey()); + ps.println(fieldsCursor.getKey()); } } ps.println(" classesByClassObject:"); - for (Map.Entry, JNIAccessibleClass> e : classesByClassObject.entrySet()) { + MapCursor, JNIAccessibleClass> cursor = classesByClassObject.getEntries(); + while (cursor.advance()) { ps.print(" "); - ps.println(e.getKey()); + ps.println(cursor.getKey()); } } } @@ -116,11 +119,11 @@ JNIAccessibleClass addClassIfAbsent(Class classObj, Function, JNIAcc @Platforms(HOSTED_ONLY.class) void addLinkages(Map linkages) { - nativeLinkages.putAll(linkages); + nativeLinkages.putAll(EconomicMap.wrapMap(linkages)); } - public Collection getClasses() { - return Collections.unmodifiableCollection(classesByClassObject.values()); + public Iterable getClasses() { + return classesByClassObject.getValues(); } public Class getClassObjectByName(String name) { @@ -145,7 +148,7 @@ public JNINativeLinkage getLinkage(String declaringClass, String name, String de } public void unsetEntryPoints(String declaringClass) { - for (JNINativeLinkage linkage : nativeLinkages.keySet()) { + for (JNINativeLinkage linkage : nativeLinkages.getKeys()) { if (declaringClass.equals(linkage.getDeclaringClassName())) { linkage.unsetEntryPoint(); } @@ -276,10 +279,11 @@ public JNIFieldId getFieldID(Class clazz, String name, boolean isStatic) { public String getFieldNameByID(Class classObject, JNIFieldId id) { JNIAccessibleClass clazz = classesByClassObject.get(classObject); if (clazz != null) { - for (Entry entry : clazz.getFieldsByName().entrySet()) { - JNIAccessibleField field = entry.getValue(); + MapCursor fieldsCursor = clazz.getFieldsByName(); + while (fieldsCursor.advance()) { + JNIAccessibleField field = fieldsCursor.getValue(); if (id.equal(field.getId())) { - return entry.getKey(); + return fieldsCursor.getKey(); } } } @@ -289,9 +293,10 @@ public String getFieldNameByID(Class classObject, JNIFieldId id) { public static JNIAccessibleMethodDescriptor getMethodDescriptor(JNIAccessibleMethod method) { if (method != null) { JNIAccessibleClass clazz = method.getDeclaringClass(); - for (Entry entry : clazz.getMethodsByDescriptor().entrySet()) { - if (entry.getValue() == method) { - return entry.getKey(); + MapCursor methodsCursor = clazz.getMethodsByDescriptor(); + while (methodsCursor.advance()) { + if (methodsCursor.getValue() == method) { + return methodsCursor.getKey(); } } } diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIFunctionTablesFeature.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIFunctionTablesFeature.java index c317c23ac4ef..602e68473758 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIFunctionTablesFeature.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIFunctionTablesFeature.java @@ -192,7 +192,7 @@ private static CFunctionPointer prepareCallTrampoline(CompilationAccessImpl acce HostedMethod hostedTrampoline = access.getUniverse().lookup(analysisTrampoline); hostedTrampoline.compilationInfo.setCustomParseFunction(trampolineMethod.createCustomParseFunction()); hostedTrampoline.compilationInfo.setCustomCompileFunction(trampolineMethod.createCustomCompileFunction()); - return MethodPointer.factory(hostedTrampoline); + return new MethodPointer(hostedTrampoline); } private static ResolvedJavaMethod getSingleMethod(MetaAccessProvider metaAccess, Class holder) { @@ -203,7 +203,7 @@ private static ResolvedJavaMethod getSingleMethod(MetaAccessProvider metaAccess, private static CFunctionPointer getStubFunctionPointer(CompilationAccessImpl access, HostedMethod method) { AnalysisMethod stub = CEntryPointCallStubSupport.singleton().getStubForMethod(method.getWrapped()); - return MethodPointer.factory(access.getUniverse().lookup(stub)); + return new MethodPointer(access.getUniverse().lookup(stub)); } private void fillJNIInvocationInterfaceTable(CompilationAccessImpl access, CFunctionPointer[] table, CFunctionPointer defaultValue) { @@ -236,7 +236,7 @@ private void fillJNIFunctionsTable(CompilationAccessImpl access, CFunctionPointe HostedMethod hostedMethod = access.getUniverse().lookup(analysisMethod); int offset = field.getOffsetInfo().getProperty(); - setFunctionPointerTable(table, offset, MethodPointer.factory(hostedMethod)); + setFunctionPointerTable(table, offset, new MethodPointer(hostedMethod)); } for (CallVariant variant : CallVariant.values()) { CFunctionPointer trampoline = prepareCallTrampoline(access, variant, false); diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIFunctions.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIFunctions.java index ac3e41004243..49c9afb150b9 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIFunctions.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIFunctions.java @@ -26,6 +26,8 @@ // Checkstyle: allow reflection +import static com.oracle.svm.core.annotate.RestrictHeapAccess.Access.NO_ALLOCATION; + import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; @@ -59,6 +61,7 @@ import com.oracle.svm.core.SubstrateDiagnostics; import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.NeverInline; +import com.oracle.svm.core.annotate.RestrictHeapAccess; import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.c.CGlobalData; @@ -72,7 +75,8 @@ import com.oracle.svm.core.log.Log; import com.oracle.svm.core.monitor.MonitorSupport; import com.oracle.svm.core.snippets.KnownIntrinsics; -import com.oracle.svm.core.thread.VMThreads; +import com.oracle.svm.core.stack.StackOverflowCheck; +import com.oracle.svm.core.thread.VMThreads.SafepointBehavior; import com.oracle.svm.core.util.Utf8; import com.oracle.svm.core.util.VMError; import com.oracle.svm.jni.JNIObjectHandles; @@ -146,8 +150,8 @@ public final class JNIFunctions { private static final Unsafe UNSAFE = GraalUnsafeAccess.getUnsafe(); - @CEntryPoint - @CEntryPointOptions(prologue = CEntryPointOptions.NoPrologue.class, epilogue = CEntryPointOptions.NoEpilogue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = CEntryPointOptions.NoPrologue.class, epilogue = CEntryPointOptions.NoEpilogue.class, publishAs = Publish.NotPublished) @Uninterruptible(reason = "No need to enter the isolate and also no way to report errors if unable to.") static int GetVersion(JNIEnvironment env) { return JNIVersion.JNI_VERSION_1_8(); @@ -157,8 +161,8 @@ static int GetVersion(JNIEnvironment env) { * jobject NewLocalRef(JNIEnv *env, jobject ref); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIObjectHandle NewLocalRef(JNIEnvironment env, JNIObjectHandle ref) { return JNIObjectHandles.newLocalRef(ref); } @@ -167,8 +171,8 @@ static JNIObjectHandle NewLocalRef(JNIEnvironment env, JNIObjectHandle ref) { * void DeleteLocalRef(JNIEnv *env, jobject localRef); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class) - @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished) static void DeleteLocalRef(JNIEnvironment env, JNIObjectHandle localRef) { JNIObjectHandles.deleteLocalRef(localRef); } @@ -177,8 +181,8 @@ static void DeleteLocalRef(JNIEnvironment env, JNIObjectHandle localRef) { * jint EnsureLocalCapacity(JNIEnv *env, jint capacity); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnJniErr.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnEDetachedOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnJniErr.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnEDetachedOnFailurePrologue.class, publishAs = Publish.NotPublished) static int EnsureLocalCapacity(JNIEnvironment env, int capacity) { if (capacity < 0) { return JNIErrors.JNI_ERR(); @@ -191,8 +195,8 @@ static int EnsureLocalCapacity(JNIEnvironment env, int capacity) { * jint PushLocalFrame(JNIEnv *env, jint capacity); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnJniErr.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnEDetachedOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnJniErr.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnEDetachedOnFailurePrologue.class, publishAs = Publish.NotPublished) static int PushLocalFrame(JNIEnvironment env, int capacity) { if (capacity < 0) { return JNIErrors.JNI_ERR(); @@ -205,8 +209,8 @@ static int PushLocalFrame(JNIEnvironment env, int capacity) { * jobject PopLocalFrame(JNIEnv *env, jobject result); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIObjectHandle PopLocalFrame(JNIEnvironment env, JNIObjectHandle handle) { Object obj = JNIObjectHandles.getObject(handle); JNIObjectHandles.popLocalFrame(); @@ -217,8 +221,8 @@ static JNIObjectHandle PopLocalFrame(JNIEnvironment env, JNIObjectHandle handle) * jboolean IsSameObject(JNIEnv *env, jobject ref1, jobject ref2); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnFalse.class) - @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnFalse.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished) static boolean IsSameObject(JNIEnvironment env, JNIObjectHandle ref1, JNIObjectHandle ref2) { Object obj1 = JNIObjectHandles.getObject(ref1); Object obj2 = JNIObjectHandles.getObject(ref2); @@ -229,8 +233,8 @@ static boolean IsSameObject(JNIEnvironment env, JNIObjectHandle ref1, JNIObjectH * jboolean IsInstanceOf(JNIEnv *env, jobject obj, jclass clazz); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnFalse.class) - @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnFalse.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished) static boolean IsInstanceOf(JNIEnvironment env, JNIObjectHandle obj, JNIObjectHandle clazz) { Object o = JNIObjectHandles.getObject(obj); if (o == null) { @@ -245,8 +249,8 @@ static boolean IsInstanceOf(JNIEnvironment env, JNIObjectHandle obj, JNIObjectHa * jclass GetObjectClass(JNIEnv *env, jobject obj); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIObjectHandle GetObjectClass(JNIEnvironment env, JNIObjectHandle handle) { Object obj = JNIObjectHandles.getObject(handle); Class clazz = obj.getClass(); @@ -257,8 +261,8 @@ static JNIObjectHandle GetObjectClass(JNIEnvironment env, JNIObjectHandle handle * jclass GetSuperclass(JNIEnv *env, jclass clazz); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIObjectHandle GetSuperclass(JNIEnvironment env, JNIObjectHandle handle) { Class clazz = JNIObjectHandles.getObject(handle); return JNIObjectHandles.createLocal(clazz.getSuperclass()); @@ -268,8 +272,8 @@ static JNIObjectHandle GetSuperclass(JNIEnvironment env, JNIObjectHandle handle) * jboolean IsAssignableFrom(JNIEnv *env, jclass clazz1, jclass clazz2); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnFalse.class) - @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnFalse.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished) static boolean IsAssignableFrom(JNIEnvironment env, JNIObjectHandle handle1, JNIObjectHandle handle2) { Class clazz1 = JNIObjectHandles.getObject(handle1); Class clazz2 = JNIObjectHandles.getObject(handle2); @@ -280,8 +284,8 @@ static boolean IsAssignableFrom(JNIEnvironment env, JNIObjectHandle handle1, JNI * jobject NewGlobalRef(JNIEnv *env, jobject obj); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class) - @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIObjectHandle NewGlobalRef(JNIEnvironment env, JNIObjectHandle handle) { return JNIObjectHandles.newGlobalRef(handle); } @@ -290,8 +294,8 @@ static JNIObjectHandle NewGlobalRef(JNIEnvironment env, JNIObjectHandle handle) * void DeleteGlobalRef(JNIEnv *env, jobject globalRef); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class) - @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished) static void DeleteGlobalRef(JNIEnvironment env, JNIObjectHandle globalRef) { JNIObjectHandles.deleteGlobalRef(globalRef); } @@ -300,8 +304,8 @@ static void DeleteGlobalRef(JNIEnvironment env, JNIObjectHandle globalRef) { * jweak NewWeakGlobalRef(JNIEnv *env, jobject obj); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIObjectHandle NewWeakGlobalRef(JNIEnvironment env, JNIObjectHandle handle) { return JNIObjectHandles.newWeakGlobalRef(handle); } @@ -310,8 +314,8 @@ static JNIObjectHandle NewWeakGlobalRef(JNIEnvironment env, JNIObjectHandle hand * void DeleteWeakGlobalRef(JNIEnv *env, jweak obj); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class) - @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished) static void DeleteWeakGlobalRef(JNIEnvironment env, JNIObjectHandle weak) { JNIObjectHandles.deleteWeakGlobalRef(weak); } @@ -320,8 +324,8 @@ static void DeleteWeakGlobalRef(JNIEnvironment env, JNIObjectHandle weak) { * jobjectRefType GetObjectRefType(JNIEnv* env, jobject obj); */ - @CEntryPoint - @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIObjectRefType GetObjectRefType(JNIEnvironment env, JNIObjectHandle handle) { try { return JNIObjectHandles.getHandleType(handle); @@ -334,8 +338,8 @@ static JNIObjectRefType GetObjectRefType(JNIEnvironment env, JNIObjectHandle han * jclass FindClass(JNIEnv *env, const char *name); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIObjectHandle FindClass(JNIEnvironment env, CCharPointer cname) { String name = Utf8.utf8ToString(cname); if (!name.startsWith("[")) { @@ -355,8 +359,8 @@ static JNIObjectHandle FindClass(JNIEnvironment env, CCharPointer cname) { * nMethods); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnJniErr.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnEDetachedOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnJniErr.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnEDetachedOnFailurePrologue.class, publishAs = Publish.NotPublished) static int RegisterNatives(JNIEnvironment env, JNIObjectHandle hclazz, JNINativeMethod methods, int nmethods) { Class clazz = JNIObjectHandles.getObject(hclazz); Pointer p = (Pointer) methods; @@ -389,8 +393,8 @@ static int RegisterNatives(JNIEnvironment env, JNIObjectHandle hclazz, JNINative * jint UnregisterNatives(JNIEnv *env, jclass clazz); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnJniErr.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnEDetachedOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnJniErr.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnEDetachedOnFailurePrologue.class, publishAs = Publish.NotPublished) static int UnregisterNatives(JNIEnvironment env, JNIObjectHandle hclazz) { Class clazz = JNIObjectHandles.getObject(hclazz); String internalName = MetaUtil.toInternalName(clazz.getName()); @@ -404,14 +408,14 @@ static int UnregisterNatives(JNIEnvironment env, JNIObjectHandle hclazz) { * jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIMethodId GetMethodID(JNIEnvironment env, JNIObjectHandle hclazz, CCharPointer cname, CCharPointer csig) { return Support.getMethodID(hclazz, cname, csig, false); } - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIMethodId GetStaticMethodID(JNIEnvironment env, JNIObjectHandle hclazz, CCharPointer cname, CCharPointer csig) { return Support.getMethodID(hclazz, cname, csig, true); } @@ -422,14 +426,14 @@ static JNIMethodId GetStaticMethodID(JNIEnvironment env, JNIObjectHandle hclazz, * jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIFieldId GetFieldID(JNIEnvironment env, JNIObjectHandle hclazz, CCharPointer cname, CCharPointer csig) { return Support.getFieldID(hclazz, cname, csig, false); } - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIFieldId GetStaticFieldID(JNIEnvironment env, JNIObjectHandle hclazz, CCharPointer cname, CCharPointer csig) { return Support.getFieldID(hclazz, cname, csig, true); } @@ -438,8 +442,8 @@ static JNIFieldId GetStaticFieldID(JNIEnvironment env, JNIObjectHandle hclazz, C * jobject AllocObject(JNIEnv *env, jclass clazz); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIObjectHandle AllocObject(JNIEnvironment env, JNIObjectHandle classHandle) { Class clazz = JNIObjectHandles.getObject(classHandle); Object instance; @@ -455,8 +459,8 @@ static JNIObjectHandle AllocObject(JNIEnvironment env, JNIObjectHandle classHand * jstring NewString(JNIEnv *env, const jchar *unicodeChars, jsize len); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIObjectHandle NewString(JNIEnvironment env, CShortPointer unicode, int len) { String str; char[] chars = new char[len]; @@ -472,8 +476,8 @@ static JNIObjectHandle NewString(JNIEnvironment env, CShortPointer unicode, int * jstring NewStringUTF(JNIEnv *env, const char *bytes); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIObjectHandle NewStringUTF(JNIEnvironment env, CCharPointer bytes) { return JNIObjectHandles.createLocal(Utf8.utf8ToString(bytes)); } @@ -482,8 +486,8 @@ static JNIObjectHandle NewStringUTF(JNIEnvironment env, CCharPointer bytes) { * jsize GetStringLength(JNIEnv *env, jstring string); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnMinusOne.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnMinusOneOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnMinusOne.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnMinusOneOnFailurePrologue.class, publishAs = Publish.NotPublished) static int GetStringLength(JNIEnvironment env, JNIObjectHandle hstr) { String str = JNIObjectHandles.getObject(hstr); return (str != null) ? str.length() : 0; @@ -493,8 +497,8 @@ static int GetStringLength(JNIEnvironment env, JNIObjectHandle hstr) { * jsize GetStringUTFLength(JNIEnv *env, jstring string); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnMinusOne.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnMinusOneOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnMinusOne.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnMinusOneOnFailurePrologue.class, publishAs = Publish.NotPublished) static int GetStringUTFLength(JNIEnvironment env, JNIObjectHandle hstr) { String str = JNIObjectHandles.getObject(hstr); return Utf8.utf8Length(str); @@ -506,14 +510,14 @@ static int GetStringUTFLength(JNIEnvironment env, JNIObjectHandle hstr) { * void ReleaseStringChars(JNIEnv *env, jstring string, const jchar *chars); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished) static CShortPointer GetStringChars(JNIEnvironment env, JNIObjectHandle hstr, CCharPointer isCopy) { return Support.getNulTerminatedStringCharsAndPin(hstr, isCopy); } - @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class) - @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished) static void ReleaseStringChars(JNIEnvironment env, JNIObjectHandle hstr, CShortPointer chars) { Support.unpinString(chars); } @@ -524,8 +528,8 @@ static void ReleaseStringChars(JNIEnvironment env, JNIObjectHandle hstr, CShortP * void ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished) static CCharPointer GetStringUTFChars(JNIEnvironment env, JNIObjectHandle hstr, CCharPointer isCopy) { String str = JNIObjectHandles.getObject(hstr); if (str == null) { @@ -538,8 +542,8 @@ static CCharPointer GetStringUTFChars(JNIEnvironment env, JNIObjectHandle hstr, return JNIThreadLocalPinnedObjects.pinArrayAndGetAddress(utf); } - @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class) - @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished) static void ReleaseStringUTFChars(JNIEnvironment env, JNIObjectHandle hstr, CCharPointer chars) { JNIThreadLocalPinnedObjects.unpinArrayByAddress(chars); } @@ -550,14 +554,14 @@ static void ReleaseStringUTFChars(JNIEnvironment env, JNIObjectHandle hstr, CCha * void ReleaseStringCritical(JNIEnv *env, jstring string, const jchar *carray); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished) static CShortPointer GetStringCritical(JNIEnvironment env, JNIObjectHandle hstr, CCharPointer isCopy) { return Support.getNulTerminatedStringCharsAndPin(hstr, isCopy); } - @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class) - @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished) static void ReleaseStringCritical(JNIEnvironment env, JNIObjectHandle hstr, CShortPointer carray) { Support.unpinString(carray); } @@ -566,8 +570,8 @@ static void ReleaseStringCritical(JNIEnvironment env, JNIObjectHandle hstr, CSho * void GetStringRegion(JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class) - @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished) static void GetStringRegion(JNIEnvironment env, JNIObjectHandle hstr, int start, int len, CShortPointer buf) { String str = JNIObjectHandles.getObject(hstr); if (start < 0) { @@ -589,8 +593,8 @@ static void GetStringRegion(JNIEnvironment env, JNIObjectHandle hstr, int start, * void GetStringUTFRegion(JNIEnv *env, jstring str, jsize start, jsize len, char *buf); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class) - @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished) static void GetStringUTFRegion(JNIEnvironment env, JNIObjectHandle hstr, int start, int len, CCharPointer buf) { String str = JNIObjectHandles.getObject(hstr); if (start < 0) { @@ -612,8 +616,8 @@ static void GetStringUTFRegion(JNIEnvironment env, JNIObjectHandle hstr, int sta * jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIObjectHandle NewDirectByteBuffer(JNIEnvironment env, WordPointer address, long capacity) { Target_java_nio_DirectByteBuffer bb = new Target_java_nio_DirectByteBuffer(address.rawValue(), (int) capacity); return JNIObjectHandles.createLocal(bb); @@ -628,8 +632,8 @@ static final class Target_java_nio_Buffer { @Alias long address; } - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished) static WordPointer GetDirectBufferAddress(JNIEnvironment env, JNIObjectHandle handle) { WordPointer address = WordFactory.nullPointer(); Object obj = JNIObjectHandles.getObject(handle); @@ -644,8 +648,8 @@ static WordPointer GetDirectBufferAddress(JNIEnvironment env, JNIObjectHandle ha * jlong GetDirectBufferCapacity(JNIEnv* env, jobject buf); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnMinusOne.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnMinusOneOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnMinusOne.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnMinusOneOnFailurePrologue.class, publishAs = Publish.NotPublished) static long GetDirectBufferCapacity(JNIEnvironment env, JNIObjectHandle hbuf) { Buffer buffer = JNIObjectHandles.getObject(hbuf); return buffer.capacity(); @@ -655,8 +659,8 @@ static long GetDirectBufferCapacity(JNIEnvironment env, JNIObjectHandle hbuf) { * jobjectArray NewObjectArray(JNIEnv *env, jsize length, jclass elementClass, jobject * initialElement); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIObjectHandle NewObjectArray(JNIEnvironment env, int length, JNIObjectHandle hElementClass, JNIObjectHandle hInitialElement) { if (length < 0) { return JNIObjectHandles.nullHandle(); @@ -674,8 +678,8 @@ static JNIObjectHandle NewObjectArray(JNIEnvironment env, int length, JNIObjectH /* * jobject GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIObjectHandle GetObjectArrayElement(JNIEnvironment env, JNIObjectHandle harray, int index) { Object[] array = JNIObjectHandles.getObject(harray); Object value = array[index]; @@ -685,8 +689,8 @@ static JNIObjectHandle GetObjectArrayElement(JNIEnvironment env, JNIObjectHandle /* * void SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class) - @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished) static void SetObjectArrayElement(JNIEnvironment env, JNIObjectHandle harray, int index, JNIObjectHandle hvalue) { Object[] array = JNIObjectHandles.getObject(harray); Object value = JNIObjectHandles.getObject(hvalue); @@ -696,8 +700,8 @@ static void SetObjectArrayElement(JNIEnvironment env, JNIObjectHandle harray, in /* * jvoid * GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished) static WordPointer GetPrimitiveArrayCritical(JNIEnvironment env, JNIObjectHandle harray, CCharPointer isCopy) { Object array = JNIObjectHandles.getObject(harray); if (array == null) { @@ -712,8 +716,8 @@ static WordPointer GetPrimitiveArrayCritical(JNIEnvironment env, JNIObjectHandle /* * void ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array, void *carray, jint mode); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class) - @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished) static void ReleasePrimitiveArrayCritical(JNIEnvironment env, JNIObjectHandle harray, WordPointer carray, int mode) { JNIThreadLocalPinnedObjects.unpinArrayByAddress(carray); } @@ -721,8 +725,8 @@ static void ReleasePrimitiveArrayCritical(JNIEnvironment env, JNIObjectHandle ha /* * jsize GetArrayLength(JNIEnv *env, jarray array); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnMinusOne.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnMinusOneOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnMinusOne.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnMinusOneOnFailurePrologue.class, publishAs = Publish.NotPublished) static int GetArrayLength(JNIEnvironment env, JNIObjectHandle harray) { /* * JNI does not specify the behavior for illegal arguments (e.g. null or non-array objects); @@ -739,14 +743,14 @@ static int GetArrayLength(JNIEnvironment env, JNIObjectHandle harray) { * jthrowable ExceptionOccurred(JNIEnv *env); */ - @CEntryPoint - @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished) static boolean ExceptionCheck(JNIEnvironment env) { return JNIThreadLocalPendingException.get() != null; } - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIObjectHandle ExceptionOccurred(JNIEnvironment env) { return JNIObjectHandles.createLocal(JNIThreadLocalPendingException.get()); } @@ -754,8 +758,8 @@ static JNIObjectHandle ExceptionOccurred(JNIEnvironment env) { /* * void ExceptionClear(JNIEnv *env); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class) - @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished) static void ExceptionClear(JNIEnvironment env) { JNIThreadLocalPendingException.clear(); } @@ -763,8 +767,8 @@ static void ExceptionClear(JNIEnvironment env) { /* * void ExceptionDescribe(JNIEnv *env); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class) - @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished) static void ExceptionDescribe(JNIEnvironment env) { Throwable t = JNIThreadLocalPendingException.get(); JNIThreadLocalPendingException.clear(); @@ -786,8 +790,8 @@ static void ExceptionDescribe(JNIEnvironment env) { /* * jint Throw(JNIEnv *env, jthrowable obj); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnZero.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnEDetachedOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnZero.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnEDetachedOnFailurePrologue.class, publishAs = Publish.NotPublished) static int Throw(JNIEnvironment env, JNIObjectHandle handle) throws Throwable { throw (Throwable) JNIObjectHandles.getObject(handle); } @@ -800,8 +804,8 @@ interface NewObjectWithObjectArrayArgFunctionPointer extends CFunctionPointer { /* * jint ThrowNew(JNIEnv *env, jclass clazz, const char *message); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnZero.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnEDetachedOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnZero.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnEDetachedOnFailurePrologue.class, publishAs = Publish.NotPublished) static int ThrowNew(JNIEnvironment env, JNIObjectHandle clazzHandle, CCharPointer message) throws Throwable { Class clazz = JNIObjectHandles.getObject(clazzHandle); JNIMethodId ctor = Support.getMethodID(clazz, "", "(Ljava/lang/String;)V", false); @@ -822,32 +826,20 @@ static int ThrowNew(JNIEnvironment env, JNIObjectHandle clazzHandle, CCharPointe /* * void FatalError(JNIEnv *env, const char *msg); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class) - @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerVoid.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterFatalOnFailurePrologue.class, publishAs = Publish.NotPublished) @NeverInline("Access of caller frame.") static void FatalError(JNIEnvironment env, CCharPointer message) { CodePointer callerIP = KnownIntrinsics.readReturnAddress(); - LogHandler logHandler = ImageSingletons.lookup(LogHandler.class); - Log log = Log.enterFatalContext(logHandler, callerIP, CTypeConversion.toJavaString(message), null); - if (log != null) { - try { - log.string("Fatal error reported via JNI: ").string(message).newline(); - VMThreads.StatusSupport.setStatusIgnoreSafepoints(); - SubstrateDiagnostics.printFatalError(log, KnownIntrinsics.readCallerStackPointer(), callerIP); - } catch (Throwable ignored) { - /* - * Ignore exceptions reported during error reporting, we are going to exit anyway. - */ - } - } - logHandler.fatalError(); + Pointer callerSP = KnownIntrinsics.readCallerStackPointer(); + Support.fatalError(callerIP, callerSP, CTypeConversion.toJavaString(message)); } /* * jint GetJavaVM(JNIEnv *env, JavaVM **vm); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnJniErr.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnEDetachedOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnJniErr.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnEDetachedOnFailurePrologue.class, publishAs = Publish.NotPublished) static int GetJavaVM(JNIEnvironment env, JNIJavaVMPointer vm) { vm.write(JNIFunctionTables.singleton().getGlobalJavaVM()); return JNIErrors.JNI_OK(); @@ -856,8 +848,8 @@ static int GetJavaVM(JNIEnvironment env, JNIJavaVMPointer vm) { /* * jfieldID FromReflectedField(JNIEnv *env, jobject field); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIFieldId FromReflectedField(JNIEnvironment env, JNIObjectHandle fieldHandle) { JNIFieldId fieldId = WordFactory.zero(); Field obj = JNIObjectHandles.getObject(fieldHandle); @@ -871,8 +863,8 @@ static JNIFieldId FromReflectedField(JNIEnvironment env, JNIObjectHandle fieldHa /* * jobject ToReflectedField(JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIObjectHandle ToReflectedField(JNIEnvironment env, JNIObjectHandle classHandle, JNIFieldId fieldId) { Field field = null; Class clazz = JNIObjectHandles.getObject(classHandle); @@ -892,8 +884,8 @@ static JNIObjectHandle ToReflectedField(JNIEnvironment env, JNIObjectHandle clas /* * jmethodID FromReflectedMethod(JNIEnv *env, jobject method); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullWord.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullWordOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIMethodId FromReflectedMethod(JNIEnvironment env, JNIObjectHandle methodHandle) { JNIMethodId methodId = WordFactory.nullPointer(); Executable method = JNIObjectHandles.getObject(methodHandle); @@ -908,8 +900,8 @@ static JNIMethodId FromReflectedMethod(JNIEnvironment env, JNIObjectHandle metho /* * jobject ToReflectedMethod(JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnNullHandle.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnNullHandleOnFailurePrologue.class, publishAs = Publish.NotPublished) static JNIObjectHandle ToReflectedMethod(JNIEnvironment env, JNIObjectHandle classHandle, JNIMethodId methodId, boolean isStatic) { Executable result = null; JNIAccessibleMethod jniMethod = JNIReflectionDictionary.getMethodByID(methodId); @@ -940,8 +932,8 @@ static JNIObjectHandle ToReflectedMethod(JNIEnvironment env, JNIObjectHandle cla /* * jint MonitorEnter(JNIEnv *env, jobject obj); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnJniErr.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnEDetachedOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnJniErr.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnEDetachedOnFailurePrologue.class, publishAs = Publish.NotPublished) static int MonitorEnter(JNIEnvironment env, JNIObjectHandle handle) { Object obj = JNIObjectHandles.getObject(handle); if (obj == null) { @@ -956,8 +948,8 @@ static int MonitorEnter(JNIEnvironment env, JNIObjectHandle handle) { /* * jint MonitorExit(JNIEnv *env, jobject obj); */ - @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnJniErr.class) - @CEntryPointOptions(prologue = JNIEnvEnterReturnEDetachedOnFailurePrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(exceptionHandler = JNIExceptionHandlerReturnJniErr.class, include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvEnterReturnEDetachedOnFailurePrologue.class, publishAs = Publish.NotPublished) static int MonitorExit(JNIEnvironment env, JNIObjectHandle handle) { Object obj = JNIObjectHandles.getObject(handle); if (obj == null) { @@ -1161,6 +1153,28 @@ static void handleException(Throwable t) { */ JNIThreadLocalPendingException.set(t); } + + @Uninterruptible(reason = "Prevent safepoints until everything is set up for the fatal error printing.", calleeMustBe = false) + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate in fatal error handling.", overridesCallers = true) + static void fatalError(CodePointer callerIP, Pointer callerSP, String message) { + SafepointBehavior.preventSafepoints(); + StackOverflowCheck.singleton().disableStackOverflowChecksForFatalError(); + + LogHandler logHandler = ImageSingletons.lookup(LogHandler.class); + Log log = Log.enterFatalContext(logHandler, callerIP, message, null); + if (log != null) { + try { + log.string("Fatal error reported via JNI: ").string(message).newline(); + SubstrateDiagnostics.printFatalError(log, callerSP, callerIP); + } catch (Throwable ignored) { + /* + * Ignore exceptions reported during error reporting, we are going to exit + * anyway. + */ + } + } + logHandler.fatalError(); + } } static final CGlobalData UNIMPLEMENTED_UNATTACHED_ERROR_MESSAGE = CGlobalDataFactory.createCString( @@ -1179,8 +1193,8 @@ static class UnimplementedWithJNIEnvArgument { /** * Stub for unimplemented JNI functionality with a JNIEnv argument. */ - @CEntryPoint - @CEntryPointOptions(prologue = JNIEnvUnimplementedPrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIEnvUnimplementedPrologue.class, publishAs = Publish.NotPublished) static int unimplemented(JNIEnvironment env) { /* * We do not catch and preserve this exception like we normally would with JNI because @@ -1206,8 +1220,8 @@ static class UnimplementedWithJavaVMArgument { /** * Stub for unimplemented JNI functionality with a JavaVM argument. */ - @CEntryPoint - @CEntryPointOptions(prologue = JNIJavaVMUnimplementedPrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIJavaVMUnimplementedPrologue.class, publishAs = Publish.NotPublished) static int unimplemented(JNIJavaVM vm) { throw VMError.shouldNotReachHere("An unimplemented JNI function was called. Please refer to the stack trace."); } diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIInvocationInterface.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIInvocationInterface.java index a12e7892a2f4..6b4e969b7354 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIInvocationInterface.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIInvocationInterface.java @@ -93,8 +93,8 @@ static class Exports { * jint JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs); */ - @CEntryPoint(name = "JNI_GetCreatedJavaVMs") - @CEntryPointOptions(prologue = NoPrologue.class, epilogue = NoEpilogue.class, publishAs = Publish.SymbolOnly, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(name = "JNI_GetCreatedJavaVMs", include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = NoPrologue.class, epilogue = NoEpilogue.class, publishAs = Publish.SymbolOnly) @Uninterruptible(reason = "No Java context.") static int JNI_GetCreatedJavaVMs(JNIJavaVMPointer vmBuf, int bufLen, CIntPointer nVMs) { JNIJavaVMList.gather(vmBuf, bufLen, nVMs); @@ -160,8 +160,8 @@ static void enter(JNIJavaVMPointer vmBuf, JNIEnvironmentPointer penv, JNIJavaVMI * @see LogHandler * @see "https://docs.oracle.com/en/java/javase/14/docs/specs/jni/invocation.html#jni_createjavavm" */ - @CEntryPoint(name = "JNI_CreateJavaVM") - @CEntryPointOptions(prologue = JNICreateJavaVMPrologue.class, publishAs = Publish.SymbolOnly, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(name = "JNI_CreateJavaVM", include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNICreateJavaVMPrologue.class, publishAs = Publish.SymbolOnly) static int JNI_CreateJavaVM(JNIJavaVMPointer vmBuf, JNIEnvironmentPointer penv, JNIJavaVMInitArgs vmArgs) { // NOTE: could check version, extra options (-verbose etc.), hooks etc. WordPointer javavmIdPointer = WordFactory.nullPointer(); @@ -206,8 +206,8 @@ public void run() { /* * jint JNI_GetDefaultJavaVMInitArgs(void *vm_args); */ - @CEntryPoint(name = "JNI_GetDefaultJavaVMInitArgs") - @CEntryPointOptions(prologue = NoPrologue.class, epilogue = NoEpilogue.class, publishAs = Publish.SymbolOnly, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(name = "JNI_GetDefaultJavaVMInitArgs", include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = NoPrologue.class, epilogue = NoEpilogue.class, publishAs = Publish.SymbolOnly) @Uninterruptible(reason = "No Java context") static int JNI_GetDefaultJavaVMInitArgs(JNIJavaVMInitArgs vmArgs) { int version = vmArgs.getVersion(); @@ -224,8 +224,8 @@ static int JNI_GetDefaultJavaVMInitArgs(JNIJavaVMInitArgs vmArgs) { /* * jint AttachCurrentThread(JavaVM *vm, void **p_env, void *thr_args); */ - @CEntryPoint - @CEntryPointOptions(prologue = JNIJavaVMEnterAttachThreadManualJavaThreadPrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIJavaVMEnterAttachThreadManualJavaThreadPrologue.class, publishAs = Publish.NotPublished) static int AttachCurrentThread(JNIJavaVM vm, JNIEnvironmentPointer penv, JNIJavaVMAttachArgs args) { return Support.attachCurrentThread(vm, penv, args, false); } @@ -233,8 +233,8 @@ static int AttachCurrentThread(JNIJavaVM vm, JNIEnvironmentPointer penv, JNIJava /* * jint AttachCurrentThreadAsDaemon(JavaVM *vm, void **p_env, void *thr_args); */ - @CEntryPoint - @CEntryPointOptions(prologue = JNIJavaVMEnterAttachThreadManualJavaThreadPrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIJavaVMEnterAttachThreadManualJavaThreadPrologue.class, publishAs = Publish.NotPublished) static int AttachCurrentThreadAsDaemon(JNIJavaVM vm, JNIEnvironmentPointer penv, JNIJavaVMAttachArgs args) { return Support.attachCurrentThread(vm, penv, args, true); } @@ -242,8 +242,8 @@ static int AttachCurrentThreadAsDaemon(JNIJavaVM vm, JNIEnvironmentPointer penv, /* * jint DetachCurrentThread(JavaVM *vm); */ - @CEntryPoint - @CEntryPointOptions(prologue = JNIJavaVMEnterAttachThreadEnsureJavaThreadPrologue.class, epilogue = LeaveDetachThreadEpilogue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIJavaVMEnterAttachThreadEnsureJavaThreadPrologue.class, epilogue = LeaveDetachThreadEpilogue.class, publishAs = Publish.NotPublished) static int DetachCurrentThread(JNIJavaVM vm) { int result = JNIErrors.JNI_OK(); if (!vm.equal(JNIFunctionTables.singleton().getGlobalJavaVM())) { @@ -257,8 +257,8 @@ static int DetachCurrentThread(JNIJavaVM vm) { /* * jint DestroyJavaVM(JavaVM *vm); */ - @CEntryPoint - @CEntryPointOptions(prologue = JNIJavaVMEnterAttachThreadEnsureJavaThreadPrologue.class, epilogue = LeaveTearDownIsolateEpilogue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIJavaVMEnterAttachThreadEnsureJavaThreadPrologue.class, epilogue = LeaveTearDownIsolateEpilogue.class, publishAs = Publish.NotPublished) @SuppressWarnings("unused") static int DestroyJavaVM(JNIJavaVM vm) { JavaThreads.singleton().joinAllNonDaemons(); @@ -268,8 +268,8 @@ static int DestroyJavaVM(JNIJavaVM vm) { /* * jint GetEnv(JavaVM *vm, void **env, jint version); */ - @CEntryPoint - @CEntryPointOptions(prologue = JNIGetEnvPrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = JNIGetEnvPrologue.class, publishAs = Publish.NotPublished) @SuppressWarnings("unused") static int GetEnv(JNIJavaVM vm, WordPointer env, int version) { env.write(JNIThreadLocalEnvironment.getAddress()); diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/hosted/JNIPrimitiveArrayOperationMethod.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/hosted/JNIPrimitiveArrayOperationMethod.java index f0ecdba39d55..d8d4cbc3e3ef 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/hosted/JNIPrimitiveArrayOperationMethod.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/hosted/JNIPrimitiveArrayOperationMethod.java @@ -29,6 +29,7 @@ import java.util.List; import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.java.FrameStateBuilder; import org.graalvm.compiler.nodes.AbstractMergeNode; @@ -262,9 +263,11 @@ private ValueNode newArray(HostedProviders providers, JNIGraphKit kit, List fTestClass; - - @Substitute - public Class getTestClass() { - return fTestClass; - } -} diff --git a/substratevm/src/com.oracle.svm.junit/src/com/oracle/svm/junit/Target_org_junit_runners_model_TestClass.java b/substratevm/src/com.oracle.svm.junit/src/com/oracle/svm/junit/Target_org_junit_runners_model_TestClass.java index 66f1ade67a62..5edc311842df 100644 --- a/substratevm/src/com.oracle.svm.junit/src/com/oracle/svm/junit/Target_org_junit_runners_model_TestClass.java +++ b/substratevm/src/com.oracle.svm.junit/src/com/oracle/svm/junit/Target_org_junit_runners_model_TestClass.java @@ -28,12 +28,11 @@ import java.lang.reflect.Constructor; -import com.oracle.svm.core.annotate.Alias; -import jdk.vm.ci.meta.MetaAccessProvider; import org.graalvm.nativeimage.hosted.RuntimeReflection; import org.junit.Assert; import org.junit.runners.model.TestClass; +import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.Inject; import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.RecomputeFieldValue.CustomFieldValueComputer; @@ -41,18 +40,20 @@ import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; +import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaField; @TargetClass(className = "org.junit.runners.model.TestClass", onlyWith = JUnitFeature.IsEnabled.class) public final class Target_org_junit_runners_model_TestClass { public static final class OnlyConstructorComputer implements CustomFieldValueComputer { - @Override public Object compute(MetaAccessProvider metaAccess, ResolvedJavaField original, ResolvedJavaField annotated, Object receiver) { - TestClass clazz = (TestClass) receiver; - if (clazz.getJavaClass() != null) { - Constructor constructor = clazz.getOnlyConstructor(); + TestClass testClass = (TestClass) receiver; + if (testClass.getJavaClass() != null) { + /* Make sure Class.forName works because Description.getTestClass can use it. */ + RuntimeReflection.register(testClass.getJavaClass()); + Constructor constructor = testClass.getOnlyConstructor(); RuntimeReflection.register(constructor); return constructor; } else { diff --git a/substratevm/src/com.oracle.svm.methodhandles/src/com/oracle/svm/methodhandles/MethodHandleFeature.java b/substratevm/src/com.oracle.svm.methodhandles/src/com/oracle/svm/methodhandles/MethodHandleFeature.java index ffd3d1f857cb..5089c3b4dfcf 100644 --- a/substratevm/src/com.oracle.svm.methodhandles/src/com/oracle/svm/methodhandles/MethodHandleFeature.java +++ b/substratevm/src/com.oracle.svm.methodhandles/src/com/oracle/svm/methodhandles/MethodHandleFeature.java @@ -41,6 +41,7 @@ import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.hosted.RuntimeReflection; +import com.oracle.svm.core.BuildPhaseProvider; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.core.invoke.MethodHandleIntrinsic; @@ -81,7 +82,6 @@ @SuppressWarnings("unused") public class MethodHandleFeature implements Feature { - private boolean analysisFinished = false; private Set seenMethodHandles; private Class directMethodHandleClass; private Class boundMethodHandleClass; @@ -176,11 +176,6 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { access.findClassByName("java.lang.invoke.VarHandle")); } - @Override - public void afterAnalysis(AfterAnalysisAccess access) { - analysisFinished = true; - } - private static void registerMHImplFunctionsForReflection(DuringAnalysisAccess access) { Class mhImplClazz = access.findClassByName("java.lang.invoke.MethodHandleImpl"); RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "checkSpreadArgument", Object.class, int.class)); @@ -194,7 +189,7 @@ private static void registerMHImplFunctionsForReflection(DuringAnalysisAccess ac private static void registerMHImplConstantHandlesForReflection(DuringAnalysisAccess access) { Class mhImplClazz = access.findClassByName("java.lang.invoke.MethodHandleImpl"); - if (JavaVersionUtil.JAVA_SPEC <= 16) { + if (JavaVersionUtil.JAVA_SPEC <= 11) { RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "copyAsPrimitiveArray", access.findClassByName("sun.invoke.util.Wrapper"), Object[].class)); RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "identity", Object[].class)); RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "fillNewArray", Integer.class, Object[].class)); @@ -283,7 +278,7 @@ private static void registerVarHandleMethodsForReflection(DuringAnalysisAccess a } private Object registerMethodHandle(Object obj) { - if (!analysisFinished) { + if (!BuildPhaseProvider.isAnalysisFinished()) { registerMethodHandleRecurse(obj); } return obj; diff --git a/substratevm/src/com.oracle.svm.methodhandles/src/com/oracle/svm/methodhandles/Target_java_lang_invoke_MethodHandleNatives.java b/substratevm/src/com.oracle.svm.methodhandles/src/com/oracle/svm/methodhandles/Target_java_lang_invoke_MethodHandleNatives.java index 71754cac83f6..2dc0fdb0ffa7 100644 --- a/substratevm/src/com.oracle.svm.methodhandles/src/com/oracle/svm/methodhandles/Target_java_lang_invoke_MethodHandleNatives.java +++ b/substratevm/src/com.oracle.svm.methodhandles/src/com/oracle/svm/methodhandles/Target_java_lang_invoke_MethodHandleNatives.java @@ -54,9 +54,9 @@ import com.oracle.svm.core.invoke.MethodHandleUtils.MethodHandlesNotSupported; import com.oracle.svm.core.invoke.MethodHandleUtils.MethodHandlesSupported; import com.oracle.svm.core.invoke.Target_java_lang_invoke_MemberName; +import com.oracle.svm.core.jdk.JDK11OrEarlier; import com.oracle.svm.core.jdk.JDK11OrLater; -import com.oracle.svm.core.jdk.JDK15OrEarlier; -import com.oracle.svm.core.jdk.JDK16OrLater; +import com.oracle.svm.core.jdk.JDK17OrLater; import com.oracle.svm.core.jdk.JDK8OrEarlier; import com.oracle.svm.reflect.target.Target_java_lang_reflect_Field; @@ -209,7 +209,7 @@ private static Object getMemberVMInfo(Target_java_lang_invoke_MemberName self) { // JDK 11 @Substitute - @TargetElement(onlyWith = {JDK11OrLater.class, JDK15OrEarlier.class}) + @TargetElement(onlyWith = {JDK11OrLater.class, JDK11OrEarlier.class}) static Target_java_lang_invoke_MemberName resolve(Target_java_lang_invoke_MemberName self, Class caller, boolean speculativeResolve) throws LinkageError, ClassNotFoundException { return Util_java_lang_invoke_MethodHandleNatives.resolve(self, caller, speculativeResolve); } @@ -230,9 +230,10 @@ private static void clearCallSiteContext(Target_java_lang_invoke_MethodHandleNat @AnnotateOriginal static native String refKindName(byte refKind); - // JDK 16 + // JDK 17 + @Substitute - @TargetElement(onlyWith = JDK16OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) static Target_java_lang_invoke_MemberName resolve(Target_java_lang_invoke_MemberName self, Class caller, int lookupMode, boolean speculativeResolve) throws LinkageError, ClassNotFoundException { Class declaringClass = self.getDeclaringClass(); @@ -353,7 +354,7 @@ public static Target_java_lang_invoke_MemberName resolve(Target_java_lang_invoke private static Method verifyAccess; static boolean verifyAccess(Class refc, Class defc, int mods, Class lookupClass, int allowedModes) { - assert JavaVersionUtil.JAVA_SPEC >= 16; + assert JavaVersionUtil.JAVA_SPEC >= 17; if (verifyAccess == null) { try { verifyAccess = VerifyAccess.class.getDeclaredMethod("isMemberAccessible", Class.class, Class.class, int.class, Class.class, Class.class, int.class); @@ -458,7 +459,7 @@ final class Target_java_lang_invoke_MethodHandleNatives_NotSupported { // JDK 11 @Delete - @TargetElement(onlyWith = {JDK11OrLater.class, JDK15OrEarlier.class}) + @TargetElement(onlyWith = {JDK11OrLater.class, JDK11OrEarlier.class}) private static native Target_java_lang_invoke_MemberName_NotSupported resolve(Target_java_lang_invoke_MemberName_NotSupported self, Class caller, boolean speculativeResolve) throws LinkageError, ClassNotFoundException; @@ -470,10 +471,10 @@ private static native Target_java_lang_invoke_MemberName_NotSupported resolve(Ta @TargetElement(onlyWith = JDK11OrLater.class) private static native void clearCallSiteContext(Target_java_lang_invoke_MethodHandleNatives_CallSiteContext context); - // JDK 16 + // JDK 17 @Delete - @TargetElement(onlyWith = JDK16OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) private static native Target_java_lang_invoke_MemberName_NotSupported resolve(Target_java_lang_invoke_MemberName_NotSupported self, Class caller, int lookupMode, boolean speculativeResolve) throws LinkageError, ClassNotFoundException; } diff --git a/substratevm/src/com.oracle.svm.methodhandles/src/com/oracle/svm/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java b/substratevm/src/com.oracle.svm.methodhandles/src/com/oracle/svm/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java index 2e5f4b55e697..81fc6211d2e7 100644 --- a/substratevm/src/com.oracle.svm.methodhandles/src/com/oracle/svm/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java +++ b/substratevm/src/com.oracle.svm.methodhandles/src/com/oracle/svm/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java @@ -37,9 +37,9 @@ import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.invoke.MethodHandleUtils.MethodHandlesSupported; import com.oracle.svm.core.invoke.Target_java_lang_invoke_MemberName; -import com.oracle.svm.core.jdk.JDK11_0_10OrEarlier; -import com.oracle.svm.core.jdk.JDK11_0_11OrLater; -import com.oracle.svm.core.jdk.JDK15OrLater; +import com.oracle.svm.core.jdk.JDK11OrLater; +import com.oracle.svm.core.jdk.JDK17OrLater; +import com.oracle.svm.core.jdk.JDK8OrEarlier; @TargetClass(value = MethodHandles.class, innerClass = "Lookup", onlyWith = MethodHandlesSupported.class) final class Target_java_lang_invoke_MethodHandles_Lookup { @@ -51,7 +51,7 @@ public Class defineClass(@SuppressWarnings("unused") byte[] bytes) { @SuppressWarnings({"static-method", "unused"}) @Substitute - @TargetElement(onlyWith = JDK11_0_10OrEarlier.class) + @TargetElement(onlyWith = JDK8OrEarlier.class) private MethodHandle maybeBindCaller(Target_java_lang_invoke_MemberName method, MethodHandle mh, Class boundCallerClass) throws IllegalAccessException { @@ -61,7 +61,7 @@ private MethodHandle maybeBindCaller(Target_java_lang_invoke_MemberName method, @SuppressWarnings({"static-method", "unused"}) @Substitute - @TargetElement(onlyWith = JDK11_0_11OrLater.class) + @TargetElement(onlyWith = JDK11OrLater.class) private MethodHandle maybeBindCaller(Target_java_lang_invoke_MemberName method, MethodHandle mh, Target_java_lang_invoke_MethodHandles_Lookup boundCaller) throws IllegalAccessException { @@ -70,19 +70,19 @@ private MethodHandle maybeBindCaller(Target_java_lang_invoke_MemberName method, } @Alias // - @TargetElement(onlyWith = JDK15OrLater.class) // + @TargetElement(onlyWith = JDK17OrLater.class) // private Class lookupClass; @Alias // - @TargetElement(onlyWith = JDK15OrLater.class) // + @TargetElement(onlyWith = JDK17OrLater.class) // private Class prevLookupClass; @Alias // - @TargetElement(onlyWith = JDK15OrLater.class) // + @TargetElement(onlyWith = JDK17OrLater.class) // private int allowedModes; @Substitute - @TargetElement(onlyWith = JDK15OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) private IllegalAccessException makeAccessException(Class targetClass) { String message = "access violation: " + targetClass; if (this == SubstrateUtil.cast(MethodHandles.publicLookup(), Target_java_lang_invoke_MethodHandles_Lookup.class)) { @@ -101,7 +101,7 @@ private IllegalAccessException makeAccessException(Class targetClass) { /** This call is a noop without the security manager. */ @SuppressWarnings("unused") @Substitute - @TargetElement(onlyWith = JDK15OrLater.class) + @TargetElement(onlyWith = JDK17OrLater.class) void checkSecurityManager(Class refc) { } } diff --git a/substratevm/src/com.oracle.svm.native.jvm.posix/src/JvmFuncs.c b/substratevm/src/com.oracle.svm.native.jvm.posix/src/JvmFuncs.c index b9968f5286f2..33982e90dc09 100644 --- a/substratevm/src/com.oracle.svm.native.jvm.posix/src/JvmFuncs.c +++ b/substratevm/src/com.oracle.svm.native.jvm.posix/src/JvmFuncs.c @@ -257,19 +257,19 @@ JNIEXPORT jlong JNICALL JVM_NanoTime(void *env, void * ignored) { } JNIEXPORT jlong JNICALL JVM_GetNanoTimeAdjustment(void *env, void * ignored, jlong offset_secs) { - long maxDiffSecs = 0x0100000000L; - long minDiffSecs = -maxDiffSecs; + int64_t maxDiffSecs = 0x0100000000LL; + int64_t minDiffSecs = -maxDiffSecs; struct timeval time; int status = gettimeofday(&time, NULL); - long seconds = time.tv_sec; - long nanos = time.tv_usec * 1000; + int64_t seconds = time.tv_sec; + int64_t nanos = time.tv_usec * 1000; - long diff = seconds - offset_secs; + int64_t diff = seconds - offset_secs; if (diff >= maxDiffSecs || diff <= minDiffSecs) { return -1; } - return diff * 1000000000 + nanos; + return diff * 1000000000LL + nanos; } JNIEXPORT jlong JNICALL Java_jdk_internal_misc_VM_getNanoTimeAdjustment(void *env, void * ignored, jlong offset_secs) { diff --git a/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c b/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c index 61fbc311b0ed..1c63fe3ae3af 100644 --- a/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c +++ b/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c @@ -25,8 +25,8 @@ #if defined(__x86_64__) || defined(_WIN64) -#include -#include +#include +#include #include "amd64cpufeatures.h" #include "amd64hotspotcpuinfo.h" @@ -550,17 +550,56 @@ void determineCPUFeatures(CPUFeatures *features) #elif defined(__aarch64__) -#include -#include -#include -#include -#include +/* + * The corresponding HotSpot code can be found in vm_version_bsd_aarch64. + */ +#if defined(__APPLE__) + +#include +#include #include "aarch64cpufeatures.h" +static uint32_t cpu_has(const char* optional) { + uint32_t val; + size_t len = sizeof(val); + if (sysctlbyname(optional, &val, &len, NULL, 0)) { + return 0; + } + return val; +} + +void determineCPUFeatures(CPUFeatures* features) { + features->fFP = !!(cpu_has("hw.optional.floatingpoint")); + features->fASIMD = !!(cpu_has("hw.optional.neon")); + features->fEVTSTRM = 0; + features->fAES = 0; + features->fPMULL = 0; + features->fSHA1 = 0; + features->fSHA2 = 0; + features->fCRC32 = !!(cpu_has("hw.optional.armv8_crc32")); + features->fLSE = !!(cpu_has("hw.optional.armv8_1_atomics")); + features->fDCPOP = 0; + features->fSHA3 = 0; + features->fSHA512 = 0; + features->fSVE = 0; + features->fSVE2 = 0; + features->fSTXRPREFETCH = 0; + features->fA53MAC = 0; + features->fDMBATOMICS = 0; +} + /* * The corresponding HotSpot code can be found in vm_version_aarch64 and * vm_version_linux_aarch64. */ +#elif defined(__linux__) + +#include +#include +#include +#include +#include +#include "aarch64cpufeatures.h" #ifndef HWCAP_FP #define HWCAP_FP (1L << 0) @@ -675,6 +714,7 @@ void determineCPUFeatures(CPUFeatures* features) { if (_cpu == CPU_CAVIUM && _model == 0xA1 && _variant == 0) features->fDMBATOMICS = 1; } +#endif #else /* diff --git a/substratevm/src/com.oracle.svm.polyglot/src/com/oracle/svm/polyglot/scala/ScalaFeature.java b/substratevm/src/com.oracle.svm.polyglot/src/com/oracle/svm/polyglot/scala/ScalaFeature.java index 8168795a2911..30e83cf26b5b 100644 --- a/substratevm/src/com.oracle.svm.polyglot/src/com/oracle/svm/polyglot/scala/ScalaFeature.java +++ b/substratevm/src/com.oracle.svm.polyglot/src/com/oracle/svm/polyglot/scala/ScalaFeature.java @@ -66,6 +66,9 @@ public boolean isInConfiguration(IsInConfigurationAccess access) { public void beforeAnalysis(BeforeAnalysisAccess access) { initializeScalaEnumerations(access); RuntimeClassInitialization.initializeAtBuildTime("scala.Symbol"); + RuntimeClassInitialization.initializeAtBuildTime("scala.Symbol$"); + /* Initialized through an invokedynamic in `scala.Option` */ + RuntimeClassInitialization.initializeAtBuildTime("scala.runtime.LambdaDeserialize"); } @Override diff --git a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionDataBuilder.java b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionDataBuilder.java index 661ea1dd667e..0a5d70ab99a0 100644 --- a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionDataBuilder.java +++ b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionDataBuilder.java @@ -231,12 +231,10 @@ private void processReachableTypes(DuringAnalysisAccessImpl access) { protected void processMethodMetadata(DuringAnalysisAccessImpl access) { if (SubstrateOptions.ConfigureReflectionMetadata.getValue()) { - /* Trigger creation of the AnalysisMethod objects needed to store metadata */ Set newQueriedMethods = new HashSet<>(); for (Executable method : queriedMethods) { if (!SubstitutionReflectivityFilter.shouldExclude(method, access.getMetaAccess(), access.getUniverse())) { - access.getMetaAccess().lookupJavaMethod(method); - registerMetadataForReflection(access, method); + registerMetadataForReflection(access, access.getMetaAccess().lookupJavaMethod(method), method); newQueriedMethods.add(method); } } @@ -248,7 +246,7 @@ protected void processMethodMetadata(DuringAnalysisAccessImpl access) { * method. */ if (method.isReachable() && method.hasJavaMethod()) { - registerMetadataForReflection(access, method.getJavaMethod()); + registerMetadataForReflection(access, method, method.getJavaMethod()); } } } @@ -256,18 +254,18 @@ protected void processMethodMetadata(DuringAnalysisAccessImpl access) { private static final Method parseAllTypeAnnotations = ReflectionUtil.lookupMethod(TypeAnnotationParser.class, "parseAllTypeAnnotations", AnnotatedElement.class); - private void registerMetadataForReflection(DuringAnalysisAccessImpl access, Executable reflectMethod) { + private void registerMetadataForReflection(DuringAnalysisAccessImpl access, AnalysisMethod analysisMethod, Executable reflectMethod) { /* * Reflection signature parsing will try to instantiate classes via Class.forName(). */ - makeTypeReachable(access, reflectMethod.getDeclaringClass(), false); + makeTypeReachable(access, analysisMethod.getDeclaringClass().getJavaClass(), false); for (TypeVariable type : reflectMethod.getTypeParameters()) { makeTypeReachable(access, type, true); } - for (Type paramType : reflectMethod.getGenericParameterTypes()) { + for (Type paramType : analysisMethod.getGenericParameterTypes()) { makeTypeReachable(access, paramType, true); } - if (reflectMethod instanceof Method) { + if (!analysisMethod.isConstructor()) { makeTypeReachable(access, ((Method) reflectMethod).getGenericReturnType(), true); } for (Type exceptionType : reflectMethod.getGenericExceptionTypes()) { @@ -277,7 +275,7 @@ private void registerMetadataForReflection(DuringAnalysisAccessImpl access, Exec /* * Enable runtime parsing of annotations */ - for (Annotation annotation : GuardedAnnotationAccess.getDeclaredAnnotations(reflectMethod)) { + for (Annotation annotation : GuardedAnnotationAccess.getDeclaredAnnotations(analysisMethod)) { makeTypeReachable(access, annotation.annotationType(), false); } for (Annotation[] parameterAnnotations : reflectMethod.getParameterAnnotations()) { @@ -304,7 +302,7 @@ private void makeTypeReachable(DuringAnalysisAccessImpl access, Type type, boole return; } seenTypes.add(type); - if (type instanceof Class) { + if (type instanceof Class && !SubstitutionReflectivityFilter.shouldExclude((Class) type, access.getMetaAccess(), access.getUniverse())) { Class clazz = (Class) type; if (access.getMetaAccess().lookupJavaType(clazz).registerAsReachable()) { access.requireAnalysisIteration(); diff --git a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionFeature.java b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionFeature.java index 827c4ea7d274..02684b29ba1e 100644 --- a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionFeature.java +++ b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionFeature.java @@ -154,7 +154,7 @@ private Object createAccessor(Executable member) { private CFunctionPointer register(ResolvedJavaMethod method) { AnalysisMethod aMethod = method instanceof AnalysisMethod ? (AnalysisMethod) method : analysisAccess.getUniverse().lookup(method); analysisAccess.registerAsCompiled(aMethod); - return MethodPointer.factory(aMethod); + return new MethodPointer(aMethod); } protected ResolvedJavaMethod createReflectiveInvokeMethod(String name, ResolvedJavaMethod prototype, Method method) { diff --git a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/target/RuntimeReflectionConstructorsImpl.java b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/target/RuntimeReflectionConstructorsImpl.java index e6a1c33372e1..ec0bcbb0d9ca 100644 --- a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/target/RuntimeReflectionConstructorsImpl.java +++ b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/target/RuntimeReflectionConstructorsImpl.java @@ -35,32 +35,32 @@ public class RuntimeReflectionConstructorsImpl implements RuntimeReflectionConstructors { @Override public Method newMethod(Class declaringClass, String name, Class[] parameterTypes, Class returnType, Class[] checkedExceptions, int modifiers, String signature, - byte[] annotations, byte[] parameterAnnotations, byte[] annotationDefault, byte[] typeAnnotations, String[] parameterNames, int[] parameterModifiers) { + byte[] annotations, byte[] parameterAnnotations, byte[] annotationDefault, byte[] typeAnnotations, String[] reflectParameterNames, int[] reflectParameterModifiers) { Target_java_lang_reflect_Method method = new Target_java_lang_reflect_Method(); method.constructor(declaringClass, name, parameterTypes, returnType, checkedExceptions, modifiers, -1, signature, annotations, parameterAnnotations, annotationDefault); - fillParameters(SubstrateUtil.cast(method, Target_java_lang_reflect_Executable.class), parameterNames, parameterModifiers); + fillReflectParameters(SubstrateUtil.cast(method, Target_java_lang_reflect_Executable.class), reflectParameterNames, reflectParameterModifiers); SubstrateUtil.cast(method, Target_java_lang_reflect_Executable.class).typeAnnotations = typeAnnotations; return SubstrateUtil.cast(method, Method.class); } @Override public Constructor newConstructor(Class declaringClass, Class[] parameterTypes, Class[] checkedExceptions, int modifiers, String signature, - byte[] annotations, byte[] parameterAnnotations, byte[] typeAnnotations, String[] parameterNames, int[] parameterModifiers) { + byte[] annotations, byte[] parameterAnnotations, byte[] typeAnnotations, String[] reflectParameterNames, int[] reflectParameterModifiers) { Target_java_lang_reflect_Constructor cons = new Target_java_lang_reflect_Constructor(); cons.constructor(declaringClass, parameterTypes, checkedExceptions, modifiers, -1, signature, annotations, parameterAnnotations); - fillParameters(SubstrateUtil.cast(cons, Target_java_lang_reflect_Executable.class), parameterNames, parameterModifiers); + fillReflectParameters(SubstrateUtil.cast(cons, Target_java_lang_reflect_Executable.class), reflectParameterNames, reflectParameterModifiers); SubstrateUtil.cast(cons, Target_java_lang_reflect_Executable.class).typeAnnotations = typeAnnotations; return SubstrateUtil.cast(cons, Constructor.class); } - private static void fillParameters(Target_java_lang_reflect_Executable executable, String[] parameterNames, int[] parameterModifiers) { - if (parameterNames != null && parameterModifiers != null) { + private static void fillReflectParameters(Target_java_lang_reflect_Executable executable, String[] reflectParameterNames, int[] reflectParameterModifiers) { + if (reflectParameterNames != null && reflectParameterModifiers != null) { executable.hasRealParameterData = true; - assert parameterNames.length == parameterModifiers.length; - executable.parameters = new Target_java_lang_reflect_Parameter[parameterNames.length]; - for (int i = 0; i < parameterNames.length; ++i) { + assert reflectParameterNames.length == reflectParameterModifiers.length; + executable.parameters = new Target_java_lang_reflect_Parameter[reflectParameterNames.length]; + for (int i = 0; i < reflectParameterNames.length; ++i) { executable.parameters[i] = new Target_java_lang_reflect_Parameter(); - executable.parameters[i].constructor(parameterNames[i], parameterModifiers[i], executable, i); + executable.parameters[i].constructor(reflectParameterNames[i], reflectParameterModifiers[i], executable, i); } } else { executable.hasRealParameterData = false; diff --git a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/target/Target_java_lang_reflect_AccessibleObject.java b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/target/Target_java_lang_reflect_AccessibleObject.java index ddb9b80dbb93..44c24aefd6e9 100644 --- a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/target/Target_java_lang_reflect_AccessibleObject.java +++ b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/target/Target_java_lang_reflect_AccessibleObject.java @@ -34,7 +34,7 @@ import com.oracle.svm.core.annotate.TargetElement; import com.oracle.svm.core.jdk.JDK11OrEarlier; import com.oracle.svm.core.jdk.JDK11OrLater; -import com.oracle.svm.core.jdk.JDK16OrLater; +import com.oracle.svm.core.jdk.JDK17OrLater; @TargetClass(value = AccessibleObject.class) public final class Target_java_lang_reflect_AccessibleObject { @@ -46,7 +46,7 @@ public final class Target_java_lang_reflect_AccessibleObject { volatile Object securityCheckCache; @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) // - @TargetElement(onlyWith = JDK16OrLater.class) // + @TargetElement(onlyWith = JDK17OrLater.class) // volatile Object accessCheckCache; @Alias // diff --git a/substratevm/src/com.oracle.svm.test.jdk11/src/com/oracle/svm/test/jdk11/AbstractServiceLoaderTest.java b/substratevm/src/com.oracle.svm.test.jdk11/src/com/oracle/svm/test/jdk11/AbstractServiceLoaderTest.java index a99c4a9e0b5b..ec31c327a764 100644 --- a/substratevm/src/com.oracle.svm.test.jdk11/src/com/oracle/svm/test/jdk11/AbstractServiceLoaderTest.java +++ b/substratevm/src/com.oracle.svm.test.jdk11/src/com/oracle/svm/test/jdk11/AbstractServiceLoaderTest.java @@ -27,6 +27,7 @@ import java.util.HashSet; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; +import java.util.ServiceLoader.Provider; import java.util.Set; import java.util.stream.Collectors; @@ -41,8 +42,8 @@ * Tests a corner case with respect to an abstract class being registered as a * {@linkplain ServiceLoader service}. Although abstract service class cannot be instantiated, it is * possible to get its {@link Class} because {@link ServiceLoader#stream()} does not force - * instantiation as it is a {@link java.util.stream.Stream} of {@link ServiceLoader.Provider}. This - * is in contrast to {@link ServiceLoader#iterator()}, which iterates the instances. + * instantiation as it is a {@link java.util.stream.Stream} of {@link Provider}. This is in contrast + * to {@link ServiceLoader#iterator()}, which iterates the instances. */ public class AbstractServiceLoaderTest { diff --git a/substratevm/src/com.oracle.svm.test.jdk11/src/com/oracle/svm/test/jdk11/NoProviderConstructorServiceLoaderTest.java b/substratevm/src/com.oracle.svm.test.jdk11/src/com/oracle/svm/test/jdk11/NoProviderConstructorServiceLoaderTest.java index a70d41a3772f..aa50b328cb90 100644 --- a/substratevm/src/com.oracle.svm.test.jdk11/src/com/oracle/svm/test/jdk11/NoProviderConstructorServiceLoaderTest.java +++ b/substratevm/src/com.oracle.svm.test.jdk11/src/com/oracle/svm/test/jdk11/NoProviderConstructorServiceLoaderTest.java @@ -67,7 +67,7 @@ public abstract static class NoProviderConstructorService implements ServiceInte /** * Not a provider constructor. This violates the contract of {@link ServiceLoader}. */ - NoProviderConstructorService(Class clazz) { + NoProviderConstructorService(@SuppressWarnings("unused") Class clazz) { } } @@ -75,7 +75,7 @@ public abstract static class NoProviderConstructorService implements ServiceInte /** * This should actually throw an {@link ServiceConfigurationError}. - * + * * @see #testLazyStreamHotspot() */ @Test @@ -89,7 +89,7 @@ public void testLazyStreamNativeImage() { /** * This should actually throw an {@link ServiceConfigurationError}. - * + * * @see #testEagerStreamHotspot() */ @Test @@ -103,7 +103,7 @@ public void testEagerStreamNativeImage() { /** * This should actually throw an {@link ServiceConfigurationError}. - * + * * @see #testEagerIteratorHotspot() */ @Test diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/GitHub1398.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/GitHub1398.java index 94e970d10946..dbec84589cc0 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/GitHub1398.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/GitHub1398.java @@ -38,7 +38,7 @@ public class GitHub1398 { public static final int PORT = 6789; - @SuppressWarnings("deprecation") // joinGroup deprecated since JDK 14 + @SuppressWarnings("deprecation") // joinGroup is deprecated after JDK 11 @Test public void testMulticast() { try { diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/JVMFuncFallbackTest.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/JVMFuncFallbackTest.java index a49e77573ed0..45b27e497c5e 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/JVMFuncFallbackTest.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/JVMFuncFallbackTest.java @@ -40,10 +40,10 @@ public class JVMFuncFallbackTest { public void testImageCodeMethods() { if (Boolean.getBoolean("never.be.true.but.compiler.doesn't.know")) { /* - * Cause image to link to JVM_Clone. This will trigger a linker error if libjvm.a does - * not contain the autogenerated JVM_* fallbacks. + * Cause image to link to JVM_IHashCode. This will trigger a linker error if libjvm.a + * does not contain the autogenerated JVM_* fallbacks. */ - Jvm.JVM_Clone(WordFactory.nullPointer()); + Jvm.JVM_IHashCode(WordFactory.nullPointer()); } } } @@ -52,5 +52,5 @@ public void testImageCodeMethods() { @CLibrary(value = "jvm", requireStatic = true) class Jvm { @CFunction(transition = CFunction.Transition.NO_TRANSITION) - public static native int JVM_Clone(Pointer jni); + public static native int JVM_IHashCode(Pointer jni); } diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/StackTraceTests.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/StackTraceTests.java index 136806e18c10..3d7f9537ccd3 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/StackTraceTests.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/StackTraceTests.java @@ -103,6 +103,7 @@ public static void a(Type type) { static final class SecurityManagerSubclass extends SecurityManager { @Override + @SuppressWarnings({"deprecation"}) // deprecated on JDK 17 protected Class[] getClassContext() { return super.getClassContext(); } diff --git a/substratevm/src/com.oracle.svm.test/src/hello/Hello.java b/substratevm/src/com.oracle.svm.test/src/hello/Hello.java index e70d133ee8ea..be7f6ab8c567 100644 --- a/substratevm/src/com.oracle.svm.test/src/hello/Hello.java +++ b/substratevm/src/com.oracle.svm.test/src/hello/Hello.java @@ -47,6 +47,12 @@ static Greeter greeter(String[] args) { } public static class DefaultGreeter extends Greeter { + + @Override + public int hashCode() { + return 42; + } + @Override public void greet() { System.out.println("Hello, world!"); diff --git a/substratevm/src/com.oracle.svm.test/src/hello/Target_hello_Hello_DefaultGreeter.java b/substratevm/src/com.oracle.svm.test/src/hello/Target_hello_Hello_DefaultGreeter.java index 1fee4b7e22ca..3ae0d2cc9dd5 100644 --- a/substratevm/src/com.oracle.svm.test/src/hello/Target_hello_Hello_DefaultGreeter.java +++ b/substratevm/src/com.oracle.svm.test/src/hello/Target_hello_Hello_DefaultGreeter.java @@ -30,12 +30,21 @@ import com.oracle.svm.core.annotate.NeverInline; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.annotate.TargetElement; @TargetClass(value = Hello.DefaultGreeter.class) final class Target_hello_Hello_DefaultGreeter { + + @SuppressWarnings("static-method") + @Substitute() + @TargetElement(name = "hashCode") + private int hashCodeSubst() { + return 24; + } + @SuppressWarnings("static-method") @Substitute - public void greet() { + private void greet() { SubstituteHelperClass substituteHelperClass = new SubstituteHelperClass(); substituteHelperClass.inlineGreet(); } diff --git a/substratevm/src/com.oracle.svm.thirdparty/src/com/oracle/svm/thirdparty/jline/JLineFeature.java b/substratevm/src/com.oracle.svm.thirdparty/src/com/oracle/svm/thirdparty/jline/JLineFeature.java deleted file mode 100644 index 85894c981ced..000000000000 --- a/substratevm/src/com.oracle.svm.thirdparty/src/com/oracle/svm/thirdparty/jline/JLineFeature.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2019, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.thirdparty.jline; - -// Checkstyle: allow reflection - -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.Stream; - -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.hosted.Feature; -import org.graalvm.nativeimage.hosted.RuntimeClassInitialization; -import org.graalvm.nativeimage.hosted.RuntimeReflection; - -import com.oracle.svm.core.annotate.AutomaticFeature; -import com.oracle.svm.core.jdk.Resources; -import com.oracle.svm.core.jni.JNIRuntimeAccess; -import com.oracle.svm.util.ReflectionUtil; - -@AutomaticFeature -final class JLineFeature implements Feature { - - /** List of the classes that access the JNI library. */ - private static final List JNI_CLASS_NAMES = Arrays.asList( - "org.fusesource.jansi.internal.CLibrary", - "org.fusesource.jansi.internal.CLibrary$WinSize", - "org.fusesource.jansi.internal.CLibrary$Termios", - "org.fusesource.jansi.internal.Kernel32", - "org.fusesource.jansi.internal.Kernel32$SMALL_RECT", - "org.fusesource.jansi.internal.Kernel32$COORD", - "org.fusesource.jansi.internal.Kernel32$CONSOLE_SCREEN_BUFFER_INFO", - "org.fusesource.jansi.internal.Kernel32$CHAR_INFO", - "org.fusesource.jansi.internal.Kernel32$KEY_EVENT_RECORD", - "org.fusesource.jansi.internal.Kernel32$MOUSE_EVENT_RECORD", - "org.fusesource.jansi.internal.Kernel32$WINDOW_BUFFER_SIZE_RECORD", - "org.fusesource.jansi.internal.Kernel32$FOCUS_EVENT_RECORD", - "org.fusesource.jansi.internal.Kernel32$MENU_EVENT_RECORD", - "org.fusesource.jansi.internal.Kernel32$INPUT_RECORD"); - - /** - * Other classes that need to be initialized at run time because they reference the JNI classes - * and/or have static state that depends on run time state. - */ - private static final List RUNTIME_INIT_CLASS_NAMES = Arrays.asList( - "org.fusesource.jansi.AnsiConsole", - "org.fusesource.jansi.WindowsAnsiOutputStream", - "org.fusesource.jansi.WindowsAnsiProcessor"); - - Class terminalFactoryClass; - - @Override - public boolean isInConfiguration(IsInConfigurationAccess access) { - terminalFactoryClass = access.findClassByName("jline.TerminalFactory"); - /* Feature is only active when JLine is on the classpath. */ - return terminalFactoryClass != null; - } - - @Override - public void duringSetup(DuringSetupAccess access) { - if (Platform.includedIn(Platform.WINDOWS.class)) { - Stream.concat(JNI_CLASS_NAMES.stream(), RUNTIME_INIT_CLASS_NAMES.stream()) - .map(access::findClassByName) - .filter(Objects::nonNull) - .forEach(RuntimeClassInitialization::initializeAtRunTime); - } - } - - @Override - public void beforeAnalysis(BeforeAnalysisAccess access) { - Object[] createMethods = Arrays.stream(terminalFactoryClass.getDeclaredMethods()) - .filter(m -> Modifier.isStatic(m.getModifiers()) && m.getName().equals("create")) - .toArray(); - access.registerReachabilityHandler(JLineFeature::registerTerminalConstructor, createMethods); - - if (Platform.includedIn(Platform.WINDOWS.class)) { - /* - * Each listed class has a native method named "init" that initializes all declared - * fields of the class using JNI. So when the "init" method gets reachable (which means - * the class initializer got reachable), we need to register all fields for JNI access. - */ - JNI_CLASS_NAMES.stream() - .map(access::findClassByName) - .filter(Objects::nonNull) - .map(jniClass -> ReflectionUtil.lookupMethod(jniClass, "init")) - .forEach(initMethod -> access.registerReachabilityHandler(a -> registerJNIFields(initMethod), initMethod)); - } - } - - private static void registerTerminalConstructor(DuringAnalysisAccess access) { - /* - * TerminalFactory.create methods instantiate the actual Terminal implementation class via - * reflection. We cannot automatically constant fold which class is going to be used, so we - * register the default for each platform. If the user manually overrides the default - * implementation class, they also need to provide a reflection configuration for that - * class. - */ - Class terminalClass = access.findClassByName(Platform.includedIn(Platform.WINDOWS.class) ? "jline.AnsiWindowsTerminal" : "jline.UnixTerminal"); - if (terminalClass != null) { - RuntimeReflection.register(terminalClass); - RuntimeReflection.register(terminalClass.getDeclaredConstructors()); - } - } - - private AtomicBoolean resourceRegistered = new AtomicBoolean(); - - private void registerJNIFields(Method initMethod) { - Class jniClass = initMethod.getDeclaringClass(); - JNIRuntimeAccess.register(jniClass.getDeclaredFields()); - - if (!resourceRegistered.getAndSet(true)) { - /* The native library that is included as a resource in the .jar file. */ - String resource = "META-INF/native/windows64/jansi.dll"; - Resources.registerResource(resource, jniClass.getClassLoader().getResourceAsStream(resource)); - } - } -} diff --git a/substratevm/src/com.oracle.svm.truffle.nfi/src/com/oracle/svm/truffle/nfi/ErrnoMirror.java b/substratevm/src/com.oracle.svm.truffle.nfi/src/com/oracle/svm/truffle/nfi/ErrnoMirror.java index 48c49e780739..753c717d03a3 100644 --- a/substratevm/src/com.oracle.svm.truffle.nfi/src/com/oracle/svm/truffle/nfi/ErrnoMirror.java +++ b/substratevm/src/com.oracle.svm.truffle.nfi/src/com/oracle/svm/truffle/nfi/ErrnoMirror.java @@ -43,7 +43,7 @@ @SuppressWarnings("static-method") public final class ErrnoMirror implements TruffleObject { - static final FastThreadLocalBytes errnoMirror = FastThreadLocalFactory.createBytes(() -> SizeOf.get(CIntPointer.class)); + static final FastThreadLocalBytes errnoMirror = FastThreadLocalFactory.createBytes(() -> SizeOf.get(CIntPointer.class), "ErrnoMirror.errnoMirror"); private static final KeysArray KEYS = new KeysArray(new String[]{"bind"}); diff --git a/substratevm/src/com.oracle.svm.truffle.nfi/src/com/oracle/svm/truffle/nfi/NativeAPIImpl.java b/substratevm/src/com.oracle.svm.truffle.nfi/src/com/oracle/svm/truffle/nfi/NativeAPIImpl.java index e428be3604ee..9ec0934e8dde 100644 --- a/substratevm/src/com.oracle.svm.truffle.nfi/src/com/oracle/svm/truffle/nfi/NativeAPIImpl.java +++ b/substratevm/src/com.oracle.svm.truffle.nfi/src/com/oracle/svm/truffle/nfi/NativeAPIImpl.java @@ -75,28 +75,28 @@ private static Target_com_oracle_truffle_nfi_backend_libffi_LibFFIContext lookup return support.resolveContextHandle(context.contextHandle()); } - @CEntryPoint - @CEntryPointOptions(prologue = EnterNativeTruffleEnvPrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = EnterNativeTruffleEnvPrologue.class, publishAs = Publish.NotPublished) static NativeTruffleContext getTruffleContext(NativeTruffleEnv env) { return env.context(); } - @CEntryPoint - @CEntryPointOptions(prologue = EnterNativeTruffleEnvPrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = EnterNativeTruffleEnvPrologue.class, publishAs = Publish.NotPublished) static TruffleObjectHandle newObjectRef(@SuppressWarnings("unused") NativeTruffleEnv env, TruffleObjectHandle handle) { TruffleNFISupport support = ImageSingletons.lookup(TruffleNFISupport.class); Object object = support.resolveHandle(handle); return support.createGlobalHandle(object); } - @CEntryPoint - @CEntryPointOptions(prologue = EnterNativeTruffleEnvPrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = EnterNativeTruffleEnvPrologue.class, publishAs = Publish.NotPublished) static void releaseObjectRef(@SuppressWarnings("unused") NativeTruffleEnv env, TruffleObjectHandle handle) { ImageSingletons.lookup(TruffleNFISupport.class).destroyGlobalHandle(handle); } - @CEntryPoint - @CEntryPointOptions(prologue = EnterNativeTruffleEnvPrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = EnterNativeTruffleEnvPrologue.class, publishAs = Publish.NotPublished) static TruffleObjectHandle releaseAndReturn(@SuppressWarnings("unused") NativeTruffleEnv env, TruffleObjectHandle handle) { TruffleNFISupport support = ImageSingletons.lookup(TruffleNFISupport.class); Object object = support.resolveHandle(handle); @@ -104,8 +104,8 @@ static TruffleObjectHandle releaseAndReturn(@SuppressWarnings("unused") NativeTr return TruffleNFISupport.createLocalHandle(object); } - @CEntryPoint - @CEntryPointOptions(prologue = EnterNativeTruffleEnvPrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = EnterNativeTruffleEnvPrologue.class, publishAs = Publish.NotPublished) static int isSameObject(@SuppressWarnings("unused") NativeTruffleEnv env, TruffleObjectHandle handle1, TruffleObjectHandle handle2) { TruffleNFISupport support = ImageSingletons.lookup(TruffleNFISupport.class); Object object1 = support.resolveHandle(handle1); @@ -113,22 +113,22 @@ static int isSameObject(@SuppressWarnings("unused") NativeTruffleEnv env, Truffl return object1 == object2 ? 1 : 0; } - @CEntryPoint - @CEntryPointOptions(prologue = EnterNativeTruffleEnvPrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = EnterNativeTruffleEnvPrologue.class, publishAs = Publish.NotPublished) static void newClosureRef(NativeTruffleEnv env, PointerBase closure) { Target_com_oracle_truffle_nfi_backend_libffi_LibFFIContext context = lookupContext(env.context()); context.newClosureRef(closure.rawValue()); } - @CEntryPoint - @CEntryPointOptions(prologue = EnterNativeTruffleEnvPrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = EnterNativeTruffleEnvPrologue.class, publishAs = Publish.NotPublished) static void releaseClosureRef(NativeTruffleEnv env, PointerBase closure) { Target_com_oracle_truffle_nfi_backend_libffi_LibFFIContext context = lookupContext(env.context()); context.releaseClosureRef(closure.rawValue()); } - @CEntryPoint - @CEntryPointOptions(prologue = EnterNativeTruffleEnvPrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = EnterNativeTruffleEnvPrologue.class, publishAs = Publish.NotPublished) static TruffleObjectHandle getClosureObject(NativeTruffleEnv env, PointerBase closure) { TruffleNFISupport support = ImageSingletons.lookup(TruffleNFISupport.class); Target_com_oracle_truffle_nfi_backend_libffi_LibFFIContext context = lookupContext(env.context()); @@ -136,8 +136,8 @@ static TruffleObjectHandle getClosureObject(NativeTruffleEnv env, PointerBase cl return support.createGlobalHandle(ret); } - @CEntryPoint - @CEntryPointOptions(prologue = GetTruffleEnvPrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = GetTruffleEnvPrologue.class, publishAs = Publish.NotPublished) static NativeTruffleEnv getTruffleEnv(NativeTruffleContext context) { TruffleNFISupport support = ImageSingletons.lookup(TruffleNFISupport.class); Target_com_oracle_truffle_nfi_backend_libffi_LibFFIContext ctx = support.resolveContextHandle(context.contextHandle()); @@ -152,8 +152,8 @@ static void enter(NativeTruffleContext context) { } } - @CEntryPoint - @CEntryPointOptions(prologue = AttachCurrentThreadPrologue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = AttachCurrentThreadPrologue.class, publishAs = Publish.NotPublished) static NativeTruffleEnv attachCurrentThread(NativeTruffleContext context) { TruffleNFISupport support = ImageSingletons.lookup(TruffleNFISupport.class); Target_com_oracle_truffle_nfi_backend_libffi_LibFFIContext ctx = support.resolveContextHandle(context.contextHandle()); @@ -172,8 +172,8 @@ static void enter(NativeTruffleContext context) { } } - @CEntryPoint - @CEntryPointOptions(prologue = EnterNativeTruffleContextPrologue.class, epilogue = LeaveDetachThreadEpilogue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = EnterNativeTruffleContextPrologue.class, epilogue = LeaveDetachThreadEpilogue.class, publishAs = Publish.NotPublished) static void detachCurrentThread(@SuppressWarnings("unused") NativeTruffleContext context) { TruffleNFISupport support = ImageSingletons.lookup(TruffleNFISupport.class); Target_com_oracle_truffle_nfi_backend_libffi_LibFFIContext ctx = support.resolveContextHandle(context.contextHandle()); diff --git a/substratevm/src/com.oracle.svm.truffle.nfi/src/com/oracle/svm/truffle/nfi/NativeClosure.java b/substratevm/src/com.oracle.svm.truffle.nfi/src/com/oracle/svm/truffle/nfi/NativeClosure.java index ddba7e7517f8..20c932efc479 100644 --- a/substratevm/src/com.oracle.svm.truffle.nfi/src/com/oracle/svm/truffle/nfi/NativeClosure.java +++ b/substratevm/src/com.oracle.svm.truffle.nfi/src/com/oracle/svm/truffle/nfi/NativeClosure.java @@ -184,10 +184,10 @@ private static PointerBase serializeStringRet(Object retValue) { } } - static final FastThreadLocalObject pendingException = FastThreadLocalFactory.createObject(Throwable.class); + static final FastThreadLocalObject pendingException = FastThreadLocalFactory.createObject(Throwable.class, "NativeClosure.pendingException"); - @CEntryPoint - @CEntryPointOptions(prologue = NoPrologue.class, epilogue = NoEpilogue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = NoPrologue.class, epilogue = NoEpilogue.class, publishAs = Publish.NotPublished) @Uninterruptible(reason = "contains prologue and epilogue for thread state transition", calleeMustBe = false) static void invokeClosureBufferRet(@SuppressWarnings("unused") ffi_cif cif, Pointer ret, WordPointer args, ClosureData user) { /* Read the C error number before transitioning into the Java state. */ @@ -238,8 +238,8 @@ private static void doInvokeClosureBufferRet(Pointer ret, WordPointer args, Clos } } - @CEntryPoint - @CEntryPointOptions(prologue = NoPrologue.class, epilogue = NoEpilogue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = NoPrologue.class, epilogue = NoEpilogue.class, publishAs = Publish.NotPublished) @Uninterruptible(reason = "contains prologue and epilogue for thread state transition", calleeMustBe = false) static void invokeClosureVoidRet(@SuppressWarnings("unused") ffi_cif cif, @SuppressWarnings("unused") WordPointer ret, WordPointer args, ClosureData user) { /* Read the C error number before transitioning into the Java state. */ @@ -271,8 +271,8 @@ private static void doInvokeClosureVoidRet(WordPointer args, ClosureData user) { lookup(user).call(args, null); } - @CEntryPoint - @CEntryPointOptions(prologue = NoPrologue.class, epilogue = NoEpilogue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = NoPrologue.class, epilogue = NoEpilogue.class, publishAs = Publish.NotPublished) @Uninterruptible(reason = "contains prologue and epilogue for thread state transition", calleeMustBe = false) static void invokeClosureStringRet(@SuppressWarnings("unused") ffi_cif cif, WordPointer ret, WordPointer args, ClosureData user) { /* Read the C error number before transitioning into the Java state. */ @@ -305,8 +305,8 @@ private static void doInvokeClosureStringRet(WordPointer ret, WordPointer args, ret.write(serializeStringRet(retValue)); } - @CEntryPoint - @CEntryPointOptions(prologue = NoPrologue.class, epilogue = NoEpilogue.class, publishAs = Publish.NotPublished, include = CEntryPointOptions.NotIncludedAutomatically.class) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(prologue = NoPrologue.class, epilogue = NoEpilogue.class, publishAs = Publish.NotPublished) @Uninterruptible(reason = "contains prologue and epilogue for thread state transition", calleeMustBe = false) static void invokeClosureObjectRet(@SuppressWarnings("unused") ffi_cif cif, WordPointer ret, WordPointer args, ClosureData user) { /* Read the C error number before transitioning into the Java state. */ diff --git a/substratevm/src/com.oracle.svm.truffle.nfi/src/com/oracle/svm/truffle/nfi/TruffleNFISupport.java b/substratevm/src/com.oracle.svm.truffle.nfi/src/com/oracle/svm/truffle/nfi/TruffleNFISupport.java index 18c449f6ed88..1466a40415ec 100644 --- a/substratevm/src/com.oracle.svm.truffle.nfi/src/com/oracle/svm/truffle/nfi/TruffleNFISupport.java +++ b/substratevm/src/com.oracle.svm.truffle.nfi/src/com/oracle/svm/truffle/nfi/TruffleNFISupport.java @@ -47,7 +47,7 @@ public abstract class TruffleNFISupport { static final Charset UTF8 = Charset.forName("utf8"); - private static final FastThreadLocalObject currentScope = FastThreadLocalFactory.createObject(LocalNativeScope.class); + private static final FastThreadLocalObject currentScope = FastThreadLocalFactory.createObject(LocalNativeScope.class, "TruffleNFISupport.currentScope"); private final ObjectHandles globalHandles; private final ObjectHandles closureHandles; diff --git a/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/PermissionsFeature.java b/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/PermissionsFeature.java index 86ca19b15d05..603181d4d98d 100644 --- a/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/PermissionsFeature.java +++ b/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/PermissionsFeature.java @@ -881,6 +881,7 @@ private void checkPermission(Permission perm) { } final class SecurityManagerHolder { + @SuppressWarnings("deprecation") // SecurityManager deprecated since 17. static final SecurityManager SECURITY_MANAGER = new SecurityManager(); } diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java index a98dac8449c5..40cb4b3c19be 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java @@ -44,8 +44,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.BooleanSupplier; -import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.truffle.api.staticobject.StaticProperty; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.ValueNode; @@ -62,6 +60,7 @@ import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.AnnotateOriginal; @@ -71,6 +70,7 @@ import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; @@ -82,7 +82,6 @@ import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; import com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl; -import com.oracle.svm.hosted.c.GraalAccess; import com.oracle.svm.hosted.meta.HostedMetaAccess; import com.oracle.svm.hosted.snippets.SubstrateGraphBuilderPlugins; import com.oracle.svm.truffle.api.SubstrateTruffleRuntime; @@ -103,6 +102,7 @@ import com.oracle.truffle.api.nodes.NodeClass; import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.profiles.Profile; +import com.oracle.truffle.api.staticobject.StaticProperty; import com.oracle.truffle.api.staticobject.StaticShape; import jdk.vm.ci.meta.JavaKind; diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateFastThreadLocal.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateFastThreadLocal.java index 0630dfe5b98e..a39dcd4e284b 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateFastThreadLocal.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateFastThreadLocal.java @@ -36,7 +36,7 @@ final class SubstrateFastThreadLocal extends GraalFastThreadLocal { static final SubstrateFastThreadLocal SINGLETON = new SubstrateFastThreadLocal(); - private static final FastThreadLocalObject CONTEXT = FastThreadLocalFactory.createObject(Object[].class) + private static final FastThreadLocalObject CONTEXT = FastThreadLocalFactory.createObject(Object[].class, "SubstrateFastThreadLocal.CONTEXT") .setAllowFloatingReads(true) .setMaxOffset(FastThreadLocal.FIRST_CACHE_LINE); diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateThreadLocalHandshake.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateThreadLocalHandshake.java index cc841c2ec78c..39cb82a86fb2 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateThreadLocalHandshake.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateThreadLocalHandshake.java @@ -65,8 +65,8 @@ public final class SubstrateThreadLocalHandshake extends ThreadLocalHandshake { static final SubstrateThreadLocalHandshake SINGLETON = new SubstrateThreadLocalHandshake(); - static final FastThreadLocalInt PENDING = FastThreadLocalFactory.createInt().setMaxOffset(FastThreadLocal.FIRST_CACHE_LINE); - static final FastThreadLocalObject STATE = FastThreadLocalFactory.createObject(TruffleSafepointImpl.class) + static final FastThreadLocalInt PENDING = FastThreadLocalFactory.createInt("SubstrateThreadLocalHandshake.PENDING").setMaxOffset(FastThreadLocal.FIRST_CACHE_LINE); + static final FastThreadLocalObject STATE = FastThreadLocalFactory.createObject(TruffleSafepointImpl.class, "SubstrateThreadLocalHandshake.STATE") .setMaxOffset(FastThreadLocal.FIRST_CACHE_LINE); @Platforms(Platform.HOSTED_ONLY.class)// diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleRuntime.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleRuntime.java index f3782dbac6ff..0a82b746a8ca 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleRuntime.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleRuntime.java @@ -50,6 +50,7 @@ import org.graalvm.nativeimage.Platform.HOSTED_ONLY; import org.graalvm.nativeimage.Platforms; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.deopt.Deoptimizer; @@ -60,7 +61,6 @@ import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.option.RuntimeOptionValues; import com.oracle.svm.core.stack.SubstrateStackIntrospection; -import com.oracle.svm.hosted.c.GraalAccess; import com.oracle.svm.truffle.TruffleSupport; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.impl.AbstractFastThreadLocal; diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolateAwareTruffleCompiler.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolateAwareTruffleCompiler.java index 3f6e10a56ea4..a55709a476ff 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolateAwareTruffleCompiler.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolateAwareTruffleCompiler.java @@ -168,8 +168,8 @@ private void sharedIsolateShutdown() { Isolates.detachThread(context); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) protected static void compilerIsolateThreadShutdown(@SuppressWarnings("unused") @CEntryPoint.IsolateThreadContext CompilerIsolateThread context) { VMRuntime.shutdown(); } @@ -179,8 +179,8 @@ protected void afterCompilation(CompilerIsolateThread context) { Isolates.detachThread(context); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ClientHandle doCompile0(@SuppressWarnings("unused") @CEntryPoint.IsolateThreadContext CompilerIsolateThread context, ClientIsolateThread client, ImageHeapRef delegateRef, @@ -232,8 +232,8 @@ private static Map decodeOptions(ClientIsolateThread client, Cli return OptionsEncoder.decode(encodedOptions); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void copyEncodedOptions(@SuppressWarnings("unused") @CEntryPoint.IsolateThreadContext ClientIsolateThread client, ClientHandle encodedOptionsHandle, PointerBase buffer) { byte[] encodedOptions = IsolatedCompileClient.get().unhand(encodedOptionsHandle); CTypeConversion.asByteBuffer(buffer, encodedOptions.length).put(encodedOptions); diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedCompilableTruffleAST.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedCompilableTruffleAST.java index 1e7fdbc4a6d0..0f0a8fe1abd1 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedCompilableTruffleAST.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedCompilableTruffleAST.java @@ -153,16 +153,16 @@ public boolean isTrivial() { return isTrivial0(IsolatedCompileContext.get().getClient(), handle); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ClientHandle getCompilationSpeculationLog0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle compilableHandle) { SubstrateCompilableTruffleAST compilable = IsolatedCompileClient.get().unhand(compilableHandle); SpeculationLog log = compilable.getCompilationSpeculationLog(); return IsolatedCompileClient.get().hand(log); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void onCompilationFailed0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle compilableHandle, CompilerHandle> serializedExceptionHandle, boolean silent, boolean bailout, boolean permanentBailout, boolean graphTooBig) { @@ -173,30 +173,30 @@ private static void onCompilationFailed0(@SuppressWarnings("unused") ClientIsola IsolatedCompileClient.get().unhand(compilableHandle).onCompilationFailed(serializedException, silent, bailout, permanentBailout, graphTooBig); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ClientHandle getReasonAndStackTrace0(@SuppressWarnings("unused") CompilerIsolateThread compiler, CompilerHandle> reasonAndStackTraceHandle) { Supplier supplier = IsolatedCompileContext.get().unhand(reasonAndStackTraceHandle); return IsolatedCompileContext.get().createStringInClient(supplier.get()); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static CompilerHandle getName0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle compilableHandle) { String name = IsolatedCompileClient.get().unhand(compilableHandle).getName(); return IsolatedCompileClient.get().createStringInCompiler(name); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static int getNonTrivialNodeCount0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle compilableHandle) { SubstrateCompilableTruffleAST compilable = IsolatedCompileClient.get().unhand(compilableHandle); return compilable.getNonTrivialNodeCount(); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static CompilerHandle getCallNodes0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle compilableHandle) { SubstrateCompilableTruffleAST compilable = IsolatedCompileClient.get().unhand(compilableHandle); TruffleCallNode[] nodes = compilable.getCallNodes(); @@ -209,8 +209,8 @@ private static CompilerHandle getCallNodes0(@Suppress } } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static CompilerHandle getCallNodes1(@SuppressWarnings("unused") CompilerIsolateThread compiler, WordPointer nodeHandleArray, int length) { IsolatedTruffleCallNode[] nodes = new IsolatedTruffleCallNode[length]; @@ -221,15 +221,15 @@ private static CompilerHandle getCallNodes1(@Suppress return IsolatedCompileContext.get().hand(nodes); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static int getCallCount0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle compilableHandle) { SubstrateCompilableTruffleAST compilable = IsolatedCompileClient.get().unhand(compilableHandle); return compilable.getCallCount(); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static boolean cancelCompilation0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle compilableHandle, ClientHandle reasonHandle) { final IsolatedCompileClient isolatedCompileClient = IsolatedCompileClient.get(); final SubstrateCompilableTruffleAST compilable = isolatedCompileClient.unhand(compilableHandle); @@ -237,16 +237,16 @@ private static boolean cancelCompilation0(@SuppressWarnings("unused") ClientIsol return compilable.cancelCompilation(reason); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void dequeueInlined0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle handle) { final IsolatedCompileClient isolatedCompileClient = IsolatedCompileClient.get(); final SubstrateCompilableTruffleAST compilable = isolatedCompileClient.unhand(handle); compilable.dequeueInlined(); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static boolean isSameOrSplit0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle compilableHandle, ClientHandle otherHandle) { @@ -255,15 +255,15 @@ private static boolean isSameOrSplit0(@SuppressWarnings("unused") ClientIsolateT return compilable.isSameOrSplit(other); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static int getKnownCallSiteCount0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle compilableHandle) { SubstrateCompilableTruffleAST compilable = IsolatedCompileClient.get().unhand(compilableHandle); return compilable.getKnownCallSiteCount(); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ClientHandle getNodeRewritingAssumption0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle handle) { CompilableTruffleAST ast = IsolatedCompileClient.get().unhand(handle); JavaConstant assumptionConstant = ast.getNodeRewritingAssumptionConstant(); @@ -271,8 +271,8 @@ private static ClientHandle getNodeRewritingAssumption0(@SuppressWar return IsolatedCompileClient.get().hand(assumption); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ClientHandle getValidRootAssumption0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle handle) { CompilableTruffleAST ast = IsolatedCompileClient.get().unhand(handle); JavaConstant assumptionConstant = ast.getValidRootAssumptionConstant(); @@ -280,8 +280,8 @@ private static ClientHandle getValidRootAssumption0(@SuppressWarning return IsolatedCompileClient.get().hand(assumption); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static boolean isTrivial0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle handle) { SubstrateCompilableTruffleAST compilable = IsolatedCompileClient.get().unhand(handle); return compilable.isTrivial(); diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedCompilationIdentifier.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedCompilationIdentifier.java index 74efce924e50..b09c3d070678 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedCompilationIdentifier.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedCompilationIdentifier.java @@ -72,14 +72,14 @@ public String toString(Verbosity verbosity) { return descriptions[ordinal]; } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void close0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle compilationHandle) { IsolatedCompileClient.get().unhand(compilationHandle).close(); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static CompilerHandle toString0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle idHandle, int verbosityOrdinal) { TruffleCompilationIdentifier id = IsolatedCompileClient.get().unhand(idHandle); String description = id.toString(VERBOSITIES[verbosityOrdinal]); diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleCallNode.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleCallNode.java index 084c59838fd7..dab534d82fe8 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleCallNode.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleCallNode.java @@ -57,23 +57,23 @@ public boolean isInliningForced() { return isInliningForced0(IsolatedCompileContext.get().getClient(), handle); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ClientHandle getCurrentCallTarget0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle nodeHandle) { TruffleCallNode node = IsolatedCompileClient.get().unhand(nodeHandle); CompilableTruffleAST target = node.getCurrentCallTarget(); return IsolatedCompileClient.get().hand((SubstrateCompilableTruffleAST) target); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static int getCallCount0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle nodeHandle) { TruffleCallNode node = IsolatedCompileClient.get().unhand(nodeHandle); return node.getCallCount(); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static boolean isInliningForced0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle nodeHandle) { TruffleCallNode node = IsolatedCompileClient.get().unhand(nodeHandle); return node.isInliningForced(); diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleCompilationTask.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleCompilationTask.java index d4e3422b2622..d39687089e1d 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleCompilationTask.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleCompilationTask.java @@ -67,32 +67,32 @@ public boolean hasNextTier() { return hasNextTier0(IsolatedCompileContext.get().getClient(), handle); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static boolean isCancelled0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle taskHandle) { return IsolatedCompileClient.get().unhand(taskHandle).isCancelled(); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static boolean isLastTier0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle taskHandle) { return IsolatedCompileClient.get().unhand(taskHandle).isLastTier(); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static boolean isFirstTier0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle taskHandle) { return IsolatedCompileClient.get().unhand(taskHandle).isFirstTier(); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static boolean hasNextTier0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle taskHandle) { return IsolatedCompileClient.get().unhand(taskHandle).hasNextTier(); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ClientHandle inliningData0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle taskHandle) { TruffleInliningData inliningData = IsolatedCompileClient.get().unhand(taskHandle).inliningData(); return IsolatedCompileClient.get().hand(inliningData); diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleCompilerEventForwarder.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleCompilerEventForwarder.java index 5e015ce40697..3ee487c86458 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleCompilerEventForwarder.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleCompilerEventForwarder.java @@ -85,28 +85,28 @@ public void onFailure(CompilableTruffleAST compilable, String reason, boolean ba } @Override - public void onCompilationRetry(CompilableTruffleAST compilable, int tier) { - onCompilationRetry0(IsolatedCompileContext.get().getClient(), contextHandle, tier); + public void onCompilationRetry(CompilableTruffleAST compilable, TruffleCompilationTask task) { + onCompilationRetry0(IsolatedCompileContext.get().getClient(), contextHandle, IsolatedCompileClient.get().hand(task)); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void onGraalTierFinished0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle contextHandle, CompilerHandle graphInfo, int nodeCount) { IsolatedEventContext context = IsolatedCompileClient.get().unhand(contextHandle); context.listener.onGraalTierFinished(context.compilable, new IsolatedGraphInfo(graphInfo, nodeCount)); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void onTruffleTierFinished0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle contextHandle, CompilerHandle graphInfo, int nodeCount) { IsolatedEventContext context = IsolatedCompileClient.get().unhand(contextHandle); context.listener.onTruffleTierFinished(context.compilable, context.task.inliningData(), new IsolatedGraphInfo(graphInfo, nodeCount)); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void onSuccess0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle contextHandle, CompilerHandle graphInfo, int nodeCount, IsolatedCompilationResultData resultData, int tier) { @@ -114,19 +114,20 @@ private static void onSuccess0(@SuppressWarnings("unused") ClientIsolateThread c context.listener.onSuccess(context.compilable, context.task.inliningData(), new IsolatedGraphInfo(graphInfo, nodeCount), new IsolatedCompilationResultInfo(resultData), tier); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void onFailure0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle contextHandle, CCharPointer reason, boolean bailout, boolean permanentBailout, int tier) { IsolatedEventContext context = IsolatedCompileClient.get().unhand(contextHandle); context.listener.onFailure(context.compilable, CTypeConversion.toJavaString(reason), bailout, permanentBailout, tier); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) - private static void onCompilationRetry0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle contextHandle, int tier) { + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) + private static void onCompilationRetry0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle contextHandle, + @SuppressWarnings("unused") ClientHandle task) { IsolatedEventContext context = IsolatedCompileClient.get().unhand(contextHandle); - context.listener.onCompilationRetry(context.compilable, tier); + context.listener.onCompilationRetry(context.compilable, context.task); } } @@ -163,8 +164,8 @@ public String[] getNodeTypes(boolean simpleNames) { return IsolatedCompileClient.get().unhand(handle); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ClientHandle getNodeTypes0(@SuppressWarnings("unused") CompilerIsolateThread compiler, CompilerHandle infoHandle, boolean simpleNames) { GraphInfo info = IsolatedCompileContext.get().unhand(infoHandle); return IsolatedCompileContext.get().createStringArrayInClient(info.getNodeTypes(simpleNames)); @@ -226,8 +227,8 @@ public int getDataPatchesCount() { return dataPatchesCount; } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ClientHandle getInfopoints0(@SuppressWarnings("unused") CompilerIsolateThread compiler, CompilerHandle infoHandle) { CompilationResultInfo info = IsolatedCompileContext.get().unhand(infoHandle); return IsolatedCompileContext.get().createStringArrayInClient(info.getInfopoints()); diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleInlining.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleInlining.java index d96b0c1cce89..5496a7ef5c49 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleInlining.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleInlining.java @@ -94,8 +94,8 @@ public void addInlinedTarget(CompilableTruffleAST target) { addInlinedTarget0(IsolatedCompileContext.get().getClient(), handle, targetHandle); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ClientHandle findCallNode0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle inliningHandle, ClientHandle callNodeConstantHandle) { @@ -105,8 +105,8 @@ private static ClientHandle findCallNode0(@SuppressWarnings("un return IsolatedCompileClient.get().hand(callNode); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static CompilerHandle getPosition0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle inliningHandle, ClientHandle callNodeConstantHandle) { @@ -120,8 +120,8 @@ private static CompilerHandle getPosition0(@Suppr position.getLineNumber(), position.getOffsetStart(), position.getOffsetEnd(), position.getNodeId()); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void addTargetToDequeue0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle providerHandle, ClientHandle targetHandle) { @@ -130,8 +130,8 @@ private static void addTargetToDequeue0(@SuppressWarnings("unused") ClientIsolat truffleInliningData.addTargetToDequeue(isolatedCompileClient.unhand(targetHandle)); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void addInlinedTarget0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle providerHandle, ClientHandle targetHandle) { @@ -140,31 +140,31 @@ private static void addInlinedTarget0(@SuppressWarnings("unused") ClientIsolateT truffleInliningData.addInlinedTarget(isolatedCompileClient.unhand(targetHandle)); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void setCallCount0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle handle, int count) { TruffleInliningData truffleInliningData = IsolatedCompileClient.get().unhand(handle); truffleInliningData.setCallCount(count); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void setInlinedCallCount0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle handle, int count) { TruffleInliningData truffleInliningData = IsolatedCompileClient.get().unhand(handle); truffleInliningData.setInlinedCallCount(count); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static int countInlinedCalls0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle handle) { TruffleInliningData truffleInliningData = IsolatedCompileClient.get().unhand(handle); return truffleInliningData.countInlinedCalls(); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static CompilerHandle createPositionInCompiler(@SuppressWarnings("unused") CompilerIsolateThread compiler, ClientHandle positionHandle, int lineNumber, int offsetStart, int offsetEnd, int nodeId) { diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleRuntimeSupport.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleRuntimeSupport.java index f8312145b6c5..a9cc201b2feb 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleRuntimeSupport.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleRuntimeSupport.java @@ -72,8 +72,8 @@ public static Consumer registerOptimizedAssumptio }; } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ClientHandle> registerOptimizedAssumptionDependency0( @SuppressWarnings("unused") ClientIsolateThread client, ClientHandle assumptionHandle) { @@ -82,8 +82,8 @@ private static ClientHandle> registerOpt return IsolatedCompileClient.get().hand(observer); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void notifyAssumption0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle> consumerHandle, ClientHandle dependencyHandle) { @@ -101,8 +101,8 @@ public static JavaConstant getCallTargetForCallNode(JavaConstant callNodeConstan return new IsolatedObjectConstant(getCallTargetForCallNode0(IsolatedCompileContext.get().getClient(), callNodeHandle), false); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ClientHandle getCallTargetForCallNode0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle callNode) { OptimizedDirectCallNode node = IsolatedCompileClient.get().unhand(callNode); @@ -127,8 +127,8 @@ public static boolean tryLog(String loggerId, CompilableTruffleAST compilable, S return false; } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static void log0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle id, ClientHandle ast, ClientHandle msg) { SubstrateTruffleRuntime runtime = (SubstrateTruffleRuntime) SubstrateTruffleRuntime.getRuntime(); @@ -146,8 +146,8 @@ public static TriState tryIsSuppressedFailure(CompilableTruffleAST compilable, S return TriState.UNDEFINED; } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static boolean isSuppressedFailure0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle ast, CompilerHandle> serializedExceptionHandle) { Supplier serializedException = () -> { @@ -158,8 +158,8 @@ private static boolean isSuppressedFailure0(@SuppressWarnings("unused") ClientIs return runtime.isSuppressedFailure(IsolatedCompileClient.get().unhand(ast), serializedException); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static ClientHandle getReasonAndStackTrace0(@SuppressWarnings("unused") CompilerIsolateThread compiler, CompilerHandle> reasonAndStackTraceHandle) { Supplier supplier = IsolatedCompileContext.get().unhand(reasonAndStackTraceHandle); return IsolatedCompileContext.get().createStringInClient(supplier.get()); diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleSourceLanguagePosition.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleSourceLanguagePosition.java index 367a6b6f63d2..26e98898cbfc 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleSourceLanguagePosition.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolatedTruffleSourceLanguagePosition.java @@ -103,29 +103,29 @@ public int getNodeId() { return nodeId; } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static CompilerHandle getDescription0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle positionHandle) { String description = IsolatedCompileClient.get().unhand(positionHandle).getDescription(); return IsolatedCompileClient.get().createStringInCompiler(description); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static CompilerHandle getURIString0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle positionHandle) { URI uri = IsolatedCompileClient.get().unhand(positionHandle).getURI(); return (uri != null) ? IsolatedCompileClient.get().createStringInCompiler(uri.toString()) : IsolatedHandles.nullHandle(); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static CompilerHandle getLanguage0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle positionHandle) { String language = IsolatedCompileClient.get().unhand(positionHandle).getLanguage(); return IsolatedCompileClient.get().createStringInCompiler(language); } - @CEntryPoint - @CEntryPointOptions(include = CEntryPointOptions.NotIncludedAutomatically.class, publishAs = CEntryPointOptions.Publish.NotPublished) + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class) + @CEntryPointOptions(publishAs = CEntryPointOptions.Publish.NotPublished) private static CompilerHandle getNodeClassName0(@SuppressWarnings("unused") ClientIsolateThread client, ClientHandle positionHandle) { String language = IsolatedCompileClient.get().unhand(positionHandle).getNodeClassName(); return IsolatedCompileClient.get().createStringInCompiler(language); diff --git a/substratevm/src/com.oracle.svm.util.jdk11/src/com/oracle/svm/util/ModuleSupport.java b/substratevm/src/com.oracle.svm.util.jdk11/src/com/oracle/svm/util/ModuleSupport.java index d33b3e208d21..7fd67edbf257 100644 --- a/substratevm/src/com.oracle.svm.util.jdk11/src/com/oracle/svm/util/ModuleSupport.java +++ b/substratevm/src/com.oracle.svm.util.jdk11/src/com/oracle/svm/util/ModuleSupport.java @@ -43,7 +43,7 @@ import jdk.internal.module.Modules; @Platforms(Platform.HOSTED_ONLY.class) -public final class ModuleSupport { +public final class ModuleSupport extends ModuleSupportBase { private ModuleSupport() { } diff --git a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ModuleSupport.java b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ModuleSupport.java index 2f451deab2d2..677786c41e06 100644 --- a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ModuleSupport.java +++ b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ModuleSupport.java @@ -35,7 +35,7 @@ import org.graalvm.nativeimage.Platforms; @Platforms(Platform.HOSTED_ONLY.class) -public final class ModuleSupport { +public final class ModuleSupport extends ModuleSupportBase { private ModuleSupport() { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK16OrLater.java b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ModuleSupportBase.java similarity index 80% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK16OrLater.java rename to substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ModuleSupportBase.java index 51b1acebf518..ccde5b99230f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK16OrLater.java +++ b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ModuleSupportBase.java @@ -22,15 +22,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk; -import java.util.function.BooleanSupplier; +package com.oracle.svm.util; -import org.graalvm.compiler.serviceprovider.JavaVersionUtil; +public class ModuleSupportBase { + + public static final String ENV_VAR_USE_MODULE_SYSTEM = "USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM"; + + public static final boolean modulePathBuild = Boolean.parseBoolean(System.getenv().get(ENV_VAR_USE_MODULE_SYSTEM)); -public class JDK16OrLater implements BooleanSupplier { - @Override - public boolean getAsBoolean() { - return JavaVersionUtil.JAVA_SPEC >= 16; - } } diff --git a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ReflectionUtil.java b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ReflectionUtil.java index c63895bbaadd..8b40bf12d983 100644 --- a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ReflectionUtil.java +++ b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ReflectionUtil.java @@ -31,7 +31,10 @@ import java.lang.reflect.Method; /** - * This class contains utility methods for commonly used reflection functionality. + * This class contains utility methods for commonly used reflection functionality. Note that lookups + * will not work on JDK 17 in cases when the field/method is filtered. See + * jdk.internal.reflect.Reflection#fieldFilterMap for more information or + * com.oracle.svm.hosted.ModuleLayerFeature for an example of a workaround in such cases. */ public final class ReflectionUtil { diff --git a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/StringUtil.java b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/StringUtil.java new file mode 100644 index 000000000000..602484d32ab5 --- /dev/null +++ b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/StringUtil.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2021, Alibaba Group Holding Limited. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.svm.util; + +import java.util.ArrayList; + +public class StringUtil { + + /** + * Similar to {@link String#split(String)} but with a fixed separator string instead of a + * regular expression. This avoids making regular expression code reachable. + */ + public static String[] split(String value, String separator) { + return split(value, separator, 0); + } + + /** + * Similar to {@link String#split(String, int)} but with a fixed separator string instead of a + * regular expression. This avoids making regular expression code reachable. + */ + public static String[] split(String value, String separator, int limit) { + int offset = 0; + int next; + ArrayList list = null; + while ((next = value.indexOf(separator, offset)) != -1) { + if (list == null) { + list = new ArrayList<>(); + } + boolean limited = limit > 0; + if (!limited || list.size() < limit - 1) { + list.add(value.substring(offset, next)); + offset = next + separator.length(); + } else { + break; + } + } + + if (offset == 0) { + /* No match found. */ + return new String[]{value}; + } + + /* Add remaining segment. */ + list.add(value.substring(offset)); + + return list.toArray(new String[list.size()]); + } +} diff --git a/substratevm/src/org.graalvm.polyglot.nativeapi/src/org/graalvm/polyglot/nativeapi/PolyglotNativeAPI.java b/substratevm/src/org.graalvm.polyglot.nativeapi/src/org/graalvm/polyglot/nativeapi/PolyglotNativeAPI.java index 2985cb89487b..c48b15321432 100644 --- a/substratevm/src/org.graalvm.polyglot.nativeapi/src/org/graalvm/polyglot/nativeapi/PolyglotNativeAPI.java +++ b/substratevm/src/org.graalvm.polyglot.nativeapi/src/org/graalvm/polyglot/nativeapi/PolyglotNativeAPI.java @@ -119,7 +119,7 @@ public final class PolyglotNativeAPI { private static ThreadLocal exceptionsTL = new ThreadLocal<>(); private static ThreadLocal errorHolder = new ThreadLocal<>(); - @SuppressWarnings("rawtypes") private static final FastThreadLocalObject handles = FastThreadLocalFactory.createObject(ThreadLocalHandles.class); + @SuppressWarnings("rawtypes") private static final FastThreadLocalObject handles = FastThreadLocalFactory.createObject(ThreadLocalHandles.class, "PolyglotNativeAPI.handles"); @SuppressWarnings("unchecked") private static ThreadLocalHandles getHandles() { diff --git a/sulong/ci.jsonnet b/sulong/ci.jsonnet index 525991f5a778..9a5bd504fae1 100644 --- a/sulong/ci.jsonnet +++ b/sulong/ci.jsonnet @@ -70,33 +70,33 @@ local sc = (import "ci_common/sulong-common.jsonnet"); }, builds: [ sc.defBuild(b) for b in [ - sc.gate + $.sulong + sc.jdk8 + sc.linux_amd64 + common.eclipse + sc.gateTags("style") + { name: "gate-sulong-style-jdk8-linux-amd64" }, - sc.gate + $.sulong + sc.jdk8 + sc.linux_amd64 + common.eclipse + common.jdt + sc.gateTags("fullbuild") + { name: "gate-sulong-fullbuild-jdk8-linux-amd64" }, + sc.gate + $.sulong + sc.labsjdk_ce_17 + sc.linux_amd64 + common.eclipse + sc.gateTags("style") + { name: "gate-sulong-style-jdk17-linux-amd64" }, + sc.gate + $.sulong + sc.labsjdk_ce_17 + sc.linux_amd64 + common.eclipse + common.jdt + sc.gateTags("fullbuild") + { name: "gate-sulong-fullbuild-jdk17-linux-amd64" }, sc.Description("Recreate generated sources (parsers, etc.) and check for modification") + - sc.gate + $.sulong + sc.jdk8 + sc.linux_amd64 + $.sulong_gate_generated_sources { name: "gate-sulong-generated-sources-jdk8-linux-amd64" }, - sc.gate + $.sulong + sc.jdk8 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.requireGCC + sc.gateTags("build,sulongMisc") + $.sulong_test_toolchain + { name: "gate-sulong-misc-jdk8-linux-amd64" }, - sc.gate + $.sulong + sc.jdk8 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.requireGCC + sc.gateTags("build,parser") + { name: "gate-sulong-parser-jdk8-linux-amd64" }, - sc.gate + $.sulong + sc.jdk8 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.gateTags("build,gcc_c") + { name: "gate-sulong-gcc_c-jdk8-linux-amd64", timelimit: "45:00" }, - sc.gate + $.sulong + sc.jdk8 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.gateTags("build,gcc_cpp") + { name: "gate-sulong-gcc_cpp-jdk8-linux-amd64", timelimit: "45:00" }, - sc.gate + $.sulong + sc.jdk8 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.requireGCC + sc.gateTags("build,gcc_fortran") + { name: "gate-sulong-gcc_fortran-jdk8-linux-amd64" }, + sc.gate + $.sulong + sc.labsjdk_ce_17 + sc.linux_amd64 + $.sulong_gate_generated_sources { name: "gate-sulong-generated-sources-jdk17-linux-amd64" }, + sc.gate + $.sulong + sc.labsjdk_ce_17 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.requireGCC + sc.gateTags("build,sulongMisc") + $.sulong_test_toolchain + { name: "gate-sulong-misc-jdk17-linux-amd64" }, + sc.gate + $.sulong + sc.labsjdk_ce_17 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.requireGCC + sc.gateTags("build,parser") + { name: "gate-sulong-parser-jdk17-linux-amd64" }, + sc.gate + $.sulong + sc.labsjdk_ce_17 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.gateTags("build,gcc_c") + { name: "gate-sulong-gcc_c-jdk17-linux-amd64", timelimit: "45:00" }, + sc.gate + $.sulong + sc.labsjdk_ce_17 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.gateTags("build,gcc_cpp") + { name: "gate-sulong-gcc_cpp-jdk17-linux-amd64", timelimit: "45:00" }, + sc.gate + $.sulong + sc.labsjdk_ce_17 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.requireGCC + sc.gateTags("build,gcc_fortran") + { name: "gate-sulong-gcc_fortran-jdk17-linux-amd64" }, # No more testing on llvm 3.8 [GR-21735] - # sc.gate + $.sulong + sc.jdk8 + sc.linux_amd64 + sc.llvm38 + sc.requireGMP + sc.requireGCC + sc.gateTags("build,sulongBasic,nwcc,llvm") + { name: "gate-sulong-basic_v38"}, - sc.gate + $.sulong + sc.jdk8 + sc.linux_amd64 + sc.llvm4 + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTags) + { name: "gate-sulong-basic-nwcc-llvm-v40-jdk8-linux-amd64" }, - sc.gate + $.sulong + sc.jdk8 + sc.linux_amd64 + sc.llvm6 + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTags) + { name: "gate-sulong-basic-nwcc-llvm-v60-jdk8-linux-amd64" }, - sc.gate + $.sulong + sc.jdk8 + sc.linux_amd64 + sc.llvm8 + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTags) + { name: "gate-sulong-basic-nwcc-llvm-v80-jdk8-linux-amd64" }, + # sc.gate + $.sulong + sc.labsjdk_ce_17 + sc.linux_amd64 + sc.llvm38 + sc.requireGMP + sc.requireGCC + sc.gateTags("build,sulongBasic,nwcc,llvm") + { name: "gate-sulong-basic_v38"}, + sc.gate + $.sulong + sc.labsjdk_ce_17 + sc.linux_amd64 + sc.llvm4 + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTags) + { name: "gate-sulong-basic-nwcc-llvm-v40-jdk17-linux-amd64" }, + sc.gate + $.sulong + sc.labsjdk_ce_17 + sc.linux_amd64 + sc.llvm6 + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTags) + { name: "gate-sulong-basic-nwcc-llvm-v60-jdk17-linux-amd64" }, + sc.gate + $.sulong + sc.labsjdk_ce_17 + sc.linux_amd64 + sc.llvm8 + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTags) + { name: "gate-sulong-basic-nwcc-llvm-v80-jdk17-linux-amd64" }, - sc.gate + $.sulong + sc.jdk8 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTagsToolchain) + { name: "gate-sulong-basic-nwcc-llvm-toolchain-jdk8-linux-amd64" }, - sc.gate + $.sulong + sc.jdk8 + sc.darwin_amd64 + sc.llvm4 + sc.gateTags(basicTags) + { name: "gate-sulong-basic-nwcc-llvm-v40-jdk8-darwin-amd64", timelimit: "0:45:00" }, - sc.gate + $.sulong + sc.jdk8 + sc.darwin_amd64 + sc.llvmBundled + sc.gateTags(basicTagsToolchain) + { name: "gate-sulong-basic-nwcc-llvm-toolchain-jdk8-darwin-amd64", timelimit: "0:45:00" }, + sc.gate + $.sulong + sc.labsjdk_ce_17 + sc.darwin_amd64 + sc.llvm4 + sc.gateTags(basicTags) + { name: "gate-sulong-basic-nwcc-llvm-v40-jdk17-darwin-amd64", timelimit: "0:45:00" }, + sc.gate + $.sulong + sc.labsjdk_ce_17 + sc.darwin_amd64 + sc.llvmBundled + sc.gateTags(basicTagsToolchain) + { name: "gate-sulong-basic-nwcc-llvm-toolchain-jdk17-darwin-amd64", timelimit: "0:45:00" }, + sc.gate + $.sulong + sc.jdk8 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTagsToolchain) + { name: "gate-sulong-basic-nwcc-llvm-toolchain-jdk8-linux-amd64" }, sc.gate + $.sulong + sc.labsjdk_ce_11 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTagsToolchain) + { name: "gate-sulong-basic-nwcc-llvm-toolchain-jdk11-linux-amd64" }, sc.gate + $.sulong + sc.labsjdk_ce_17 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTagsToolchain) + { name: "gate-sulong-basic-nwcc-llvm-toolchain-jdk17-linux-amd64" }, sc.Description("Run ruby downstream tests") + - sc.gate + $.sulong + sc.jdk8 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + $.sulong_ruby_downstream_test + { name: "gate-sulong-ruby-downstream-jdk8-linux-amd64" }, + sc.gate + $.sulong + sc.labsjdk_ce_17 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + $.sulong_ruby_downstream_test + { name: "gate-sulong-ruby-downstream-jdk17-linux-amd64" }, - sc.gate + $.sulong + sc.labsjdk_ce_11 + sc.linux_aarch64 + sc.llvmBundled + sc.requireGMP + sc.gateTags(basicTagsNoNWCC) + { name: "gate-sulong-basic-llvm-jdk11-linux-aarch64", timelimit: "30:00" }, + sc.gate + $.sulong + sc.labsjdk_ce_17 + sc.linux_aarch64 + sc.llvmBundled + sc.requireGMP + sc.gateTags(basicTagsNoNWCC) + { name: "gate-sulong-basic-llvm-jdk17-linux-aarch64", timelimit: "30:00" }, - sc.weekly + $.sulong + sc.jdk8 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.requireGCC + sc.sulong_weekly_notifications + $.sulong_coverage { name: "weekly-sulong-coverage-jdk8-linux-amd64" }, + sc.weekly + $.sulong + sc.labsjdk_ce_17 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.requireGCC + sc.sulong_weekly_notifications + $.sulong_coverage { name: "weekly-sulong-coverage-jdk17-linux-amd64" }, ]], } diff --git a/sulong/mx.sulong/mx_sulong.py b/sulong/mx.sulong/mx_sulong.py index e71de3b8fcc7..634185973afb 100644 --- a/sulong/mx.sulong/mx_sulong.py +++ b/sulong/mx.sulong/mx_sulong.py @@ -233,15 +233,6 @@ def runLLVM(args=None, out=None, err=None, timeout=None, nonZeroIsFatal=True, ge dists.append('CHROMEINSPECTOR') return mx.run_java(getCommonOptions(False) + vmArgs + get_classpath_options(dists) + ["com.oracle.truffle.llvm.launcher.LLVMLauncher"] + sulongArgs, timeout=timeout, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err) -@mx.command(_suite.name, "llimul") -def runLLVMMul(args=None, out=None, err=None, timeout=None, nonZeroIsFatal=True, get_classpath_options=getClasspathOptions): - """uses Sulong to execute a LLVM IR file""" - vmArgs, sulongArgs = truffle_extract_VM_args(args) - dists = [] - if "tools" in (s.name for s in mx.suites()): - dists.append('CHROMEINSPECTOR') - return mx.run_java(getCommonOptions(False) + vmArgs + get_classpath_options(dists) + ["com.oracle.truffle.llvm.launcher.LLVMMultiContextLauncher"] + sulongArgs, timeout=timeout, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err) - @mx.command(_suite.name, "lli") def lli(args=None, out=None): """run lli via the current GraalVM""" @@ -314,8 +305,12 @@ def _open_for_reading(path): _env_flags = os.environ['CPPFLAGS'].split(' ') -mx_benchmark.add_bm_suite(mx_sulong_benchmarks.SulongBenchmarkSuite()) - +# Legacy bm suite +mx_benchmark.add_bm_suite(mx_sulong_benchmarks.SulongBenchmarkSuite(False)) +# Polybench bm suite +mx_benchmark.add_bm_suite(mx_sulong_benchmarks.SulongBenchmarkSuite(True)) +# LLVM unit tests suite +mx_benchmark.add_bm_suite(mx_sulong_benchmarks.LLVMUnitTestsSuite()) _toolchains = {} @@ -504,25 +499,3 @@ def _get_jar_dists(self): ], installable=False, )) - -mx_sdk_vm.register_graalvm_component(mx_sdk_vm.GraalVmLanguage( - suite=_suite, - name='LLVM Multi-Context Runtime Launcher', - short_name='llmulrl', - dir_name='llvm', - license_files=[], - third_party_license_files=[], - dependencies=[], - truffle_jars=[], - support_distributions=[], - launcher_configs=[ - mx_sdk_vm.LanguageLauncherConfig( - destination='bin/', - jar_distributions=['sulong:SULONG_LAUNCHER'], - main_class='com.oracle.truffle.llvm.launcher.LLVMMultiContextLauncher', - build_args=[], - language='llvm', - ), - ], - installable=False, -)) diff --git a/sulong/mx.sulong/mx_sulong_benchmarks.py b/sulong/mx.sulong/mx_sulong_benchmarks.py index 5a31be18842b..92c743601aa3 100644 --- a/sulong/mx.sulong/mx_sulong_benchmarks.py +++ b/sulong/mx.sulong/mx_sulong_benchmarks.py @@ -63,11 +63,25 @@ def _parse_results_gen(): yield r return (x for x in _parse_results_gen()) +class PolybenchExcludeWarmupRule(mx_benchmark.StdOutRule): + """Rule that behaves as the StdOutRule, but skips input until a certain pattern.""" -class SulongBenchmarkSuite(VmBenchmarkSuite): def __init__(self, *args, **kwargs): + self.startPattern = re.compile(kwargs.pop('startPattern')) + super(PolybenchExcludeWarmupRule, self).__init__(*args, **kwargs) + + def parse(self, text): + m = self.startPattern.search(text) + if m: + return super(PolybenchExcludeWarmupRule, self).parse(text[m.end()+1:]) + else: + return [] + +class SulongBenchmarkSuite(VmBenchmarkSuite): + def __init__(self, use_polybench, *args, **kwargs): super(SulongBenchmarkSuite, self).__init__(*args, **kwargs) self.bench_to_exec = {} + self.use_polybench = use_polybench def group(self): return 'Graal' @@ -76,7 +90,7 @@ def subgroup(self): return 'sulong' def name(self): - return 'csuite' + return 'csuite-polybench' if self.use_polybench else 'csuite' def run(self, benchnames, bmSuiteArgs): vm = self.get_vm_registry().get_vm_from_suite_args(bmSuiteArgs) @@ -101,7 +115,11 @@ def run(self, benchnames, bmSuiteArgs): # prepare_env adds CC, CXX, CFLAGS, etc... and we copy the environment to avoid modifying the default one. env = vm.prepare_env(env) - out = os.path.join(bench_out_dir, vm.out_file()) + outName = vm.out_file() + if self.use_polybench: + env['POLYBENCH'] = 'y' + outName += '.so' + out = os.path.join(bench_out_dir, outName) cmdline = ['make', '-f', '../Makefile', out] if mx._opts.verbose: # The Makefiles should have logic to disable the @ sign @@ -137,11 +155,21 @@ def flakySkipPatterns(self, benchmarks, bmSuiteArgs): # preparatory benchmark is run using the llimul launcher and passing --multi-context-runs=0. # We can capture this argument here and instruct the benchmark infrastructure to ignore # the output of this benchmark. - if any(a == "--multi-context-runs=0" for a in bmSuiteArgs): - return [re.compile(r'.*', re.MULTILINE)] + if self.use_polybench: + if any(a == "store-aux-engine-cache" for a in bmSuiteArgs): + return [re.compile(r'.*', re.MULTILINE)] + else: + if any(a == "--multi-context-runs=0" for a in bmSuiteArgs): + return [re.compile(r'.*', re.MULTILINE)] return [] def rules(self, out, benchmarks, bmSuiteArgs): + if self.use_polybench: + return self.polybenchRules(out, benchmarks, bmSuiteArgs) + else: + return self.legacyRules(out, benchmarks, bmSuiteArgs) + + def legacyRules(self, out, benchmarks, bmSuiteArgs): return [ SulongBenchmarkRule( r'^run (?P[\d]+) first [\d]+ warmup iterations (?P[\S]+):(?P([ ,]+(?:\d+(?:\.\d+)?))+)', @@ -211,28 +239,79 @@ def rules(self, out, benchmarks, bmSuiteArgs): }), ] + def polybenchRules(self, output, benchmarks, bmSuiteArgs): + rules = [ + mx_benchmark.StdOutRule(r"\[(?P.*)\] iteration ([0-9]*): (?P.*) (?P.*)", { + "bench-suite": "csuite", + "benchmark": benchmarks[0], + "metric.better": "lower", + "metric.name": "warmup", + "metric.unit": ("", str), + "metric.value": ("", float), + "metric.type": "numeric", + "metric.score-function": "id", + "metric.iteration": ("$iteration", int), + }), + PolybenchExcludeWarmupRule(r"\[(?P.*)\] iteration (?P[0-9]*): (?P.*) (?P.*)", { + "bench-suite": "csuite", + "benchmark": benchmarks[0], + "metric.better": "lower", + "metric.name": "time", + "metric.unit": ("", str), + "metric.value": ("", float), + "metric.type": "numeric", + "metric.score-function": "id", + "metric.iteration": ("", int), + }, startPattern=r"::: Running :::") + ] + return rules + + def _get_metric_name(self, bmSuiteArgs): + metric = None + for arg in bmSuiteArgs: + if arg.startswith("--metric="): + metric = arg[len("--metric="):] + break + if metric == "compilation-time": + return "compile-time" + elif metric == "partial-evaluation-time": + return "pe-time" + elif metric == "one-shot": + return "one-shot" + else: + return "time" + def workingDirectory(self, benchmarks, bmSuiteArgs): if len(benchmarks) != 1: mx.abort( "Please run a specific benchmark (mx benchmark csuite:) or all the benchmarks (mx benchmark csuite:*)") vm = self.get_vm_registry().get_vm_from_suite_args(bmSuiteArgs) assert isinstance(vm, CExecutionEnvironmentMixin) - return join(_benchmarksDirectory(), benchmarks[0], vm.bin_dir()) + + if self.use_polybench and (any(a == "store-aux-engine-cache" for a in bmSuiteArgs) or any(a == "load-aux-engine-cache" for a in bmSuiteArgs)): + # When storing or loading an aux engine cache, the working directory must be the same (the cache for the source is selected by its URL) + return join(_benchmarksDirectory(), benchmarks[0], 'aux-engine-cache') + else: + return join(_benchmarksDirectory(), benchmarks[0], vm.bin_dir()) def createCommandLineArgs(self, benchmarks, bmSuiteArgs): if len(benchmarks) != 1: mx.abort("Please run a specific benchmark (mx benchmark csuite:) or all the benchmarks (mx benchmark csuite:*)") + vm = self.get_vm_registry().get_vm_from_suite_args(bmSuiteArgs) + assert isinstance(vm, CExecutionEnvironmentMixin) + bmSuiteArgs = [a.replace("${benchmark}", benchmarks[0]) for a in vm.templateOptions() + bmSuiteArgs] vmArgs = self.vmArgs(bmSuiteArgs) runArgs = self.runArgs(bmSuiteArgs) try: - runArgs += ['--time', str(int(time.clock_gettime(time.CLOCK_REALTIME) * 1000000))] + if not self.use_polybench: + runArgs += ['--time', str(int(time.clock_gettime(time.CLOCK_REALTIME) * 1000000))] except: # We can end up here in case the python version we're running on doesn't have clock_gettime or CLOCK_REALTIME. pass return vmArgs + [self.bench_to_exec[benchmarks[0]]] + runArgs def get_vm_registry(self): - return native_vm_registry + return native_polybench_vm_registry if self.use_polybench else native_vm_registry class CExecutionEnvironmentMixin(object): @@ -246,6 +325,8 @@ def bin_dir(self): def prepare_env(self, env): return env + def templateOptions(self): + return [] def add_run_numbers(out): # Prepending the summary lines by the run number @@ -437,15 +518,204 @@ def launcher_args(self, args): def hosting_registry(self): return java_vm_registry -class SulongMultiContextVm(SulongVm): + +class PolybenchVm(CExecutionEnvironmentMixin, GuestVm): + + def __init__(self, config_name, options, templateOptions, host_vm=None): + super(PolybenchVm, self).__init__(host_vm) + self._config_name = config_name + self._options = options + self._templateOptions = templateOptions + + def with_host_vm(self, host_vm): + return PolybenchVm(self._config_name, self._options, self._templateOptions, host_vm) + + def config_name(self): + return self._config_name + + def toolchain_name(self): + return "native" + def name(self): - return "sulong-multi" + return "sulong-polybench" def launcherClass(self): - return "com.oracle.truffle.llvm.launcher.LLVMMultiContextLauncher" + return "org.graalvm.polybench.PolyBenchLauncher" def launcherName(self): - return "llimul" + return "polybench" + + def run(self, cwd, args): + bench_file = args[-1:] + bench_args = args[:-1] + launcher_args = ['--path'] + bench_file + self._options + bench_args + if hasattr(self.host_vm(), 'run_launcher'): + result = self.host_vm().run_launcher(self.launcherName(), launcher_args, cwd) + else: + def _filter_properties(args): + props = [] + remaining_args = [] + vm_prefix = "--vm.D" + for arg in args: + if arg.startswith(vm_prefix): + props.append('-D' + arg[len(vm_prefix):]) + else: + remaining_args.append(arg) + return props, remaining_args + + props, launcher_args = _filter_properties(launcher_args) + sulongCmdLine = self.launcher_vm_args() + \ + props + \ + ['-XX:-UseJVMCIClassLoader', self.launcherClass(), '--path'] + bench_file + launcher_args + result = self.host_vm().run(cwd, sulongCmdLine) + + ret_code, out, vm_dims = result + return ret_code, add_run_numbers(out), vm_dims + + def prepare_env(self, env): + # if hasattr(self.host_vm(), 'run_launcher'): + # import mx_sdk_vm_impl + # env['CC'] = os.path.join(mx_sdk_vm_impl.graalvm_home(fatalIfMissing=True), 'jre', 'languages', 'llvm', self.toolchain_name(), 'bin', 'graalvm-{}-clang'.format(self.toolchain_name())) + # else: + # we always use the bootstrap toolchain since the toolchain is not installed by default in a graalvm + # change this if we can properly install components into a graalvm deployment + env['CC'] = mx_subst.path_substitutions.substitute(''.format(self.toolchain_name())) + env['CXX'] = mx_subst.path_substitutions.substitute(''.format(self.toolchain_name())) + return env + + def out_file(self): + return 'bench' + + def opt_phases(self): + return [] + + def templateOptions(self): + return self._templateOptions + + def launcher_vm_args(self): + return mx_sulong.getClasspathOptions(['POLYBENCH']) + + def launcher_args(self, args): + launcher_args = [ + '--experimental-options', + '--engine.CompilationFailureAction=ExitVM', + '--engine.TreatPerformanceWarningsAsErrors=call,instanceof,store', + ] + return launcher_args + args + + def hosting_registry(self): + return java_vm_registry + +class LLVMUnitTestsSuite(VmBenchmarkSuite): + def __init__(self, *args, **kwargs): + super(LLVMUnitTestsSuite, self).__init__(*args, **kwargs) + self.bench_to_exec = {} + + def group(self): + return 'Graal' + + def subgroup(self): + return 'sulong' + + def name(self): + return 'llvm-unit-tests' + + def benchmarkList(self, bmSuiteArgs): + return ['llvm-test-suite'] + + def failurePatterns(self): + return [] + + def successPatterns(self): + return [re.compile(r'Testing Time')] + + def rules(self, out, benchmarks, bmSuiteArgs): + return [ + mx_benchmark.StdOutRule( + r'Passed:(\s+)(?P[\d]+)', + { + "benchmark": ("llvm-unit-tests", str), + # TODO: it's a borrowed metric name, a new one should be registered + "metric.name": "jck-passed", + "metric.type": "numeric", + "metric.value": ("", int), + "metric.score-function": "id", + "metric.better": "higher", + "metric.unit": "#" + }), + mx_benchmark.StdOutRule( + r'Failed:(\s+)(?P[\d]+)', + { + "benchmark": ("llvm-unit-tests", str), + # TODO: it's a borrowed metric name, a new one should be registered + "metric.name": "jck-failed", + "metric.type": "numeric", + "metric.value": ("", int), + "metric.score-function": "id", + "metric.better": "lower", + "metric.unit": "#" + }), + mx_benchmark.StdOutRule( + r'Testing Time:(\s+)(?P