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 extends Phase> phase : insertReadReplacementBeforePositions) {
+ for (Class extends BasePhase super CoreProviders>> 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
+ *
+ * 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 extends FloatingNode> 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 extends AbstractNewArrayNode> 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 super CoreProviders> 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 super CoreProviders> 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 extends VariableElement> 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 extends AbstractMemoryCheckpoint> type, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind, int bci) {
+ public BasicArrayCopyNode(NodeClass extends BasicArrayCopyNode> 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 extends AbstractMemoryCheckpoint> type, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind) {
+ public BasicArrayCopyNode(NodeClass extends BasicArrayCopyNode> 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 extends MacroNode> 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 extends MacroStateSplitWithExceptionNode> c, MacroParams p) {
+ protected MacroWithExceptionNode(NodeClass extends MacroWithExceptionNode> 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